Extrem präzise Zahlen in C#

multimolti

Erfahrenes Mitglied
Hallo!

Ich brauche für mein Projekt eine Klasse, die extrem präzise und große Zahlen verarbeiten kann. Ich weiß, dass es viele BigInteger und BigNumber Klassen gibt, die können aber alle nicht mit Nachkommastellen rechnen.
Ich bräuche irgendwas, was mit vielleicht 1000 Nachkommastellen und Zahlen mit 30000 Ziffern rechnen kann und dabei nicht zu viel Speicherplatz braucht (also nicht als String gespeichert wird oder so ein Quatsch). Das Ganze sollte am Besten auch noch schnell rechnen und alle Standardoperationen unterstützen (Addition, Subtraktion, Multiplikation, Division).

Kennt jemand sowas? Habe im Internet leider nichts gefunden!
 
Wo ist das Problem, wenn die vorhandenen Klassen keine Nachkommastellen verarbeiten?
Erweitere diese Klassen doch um Nachkomma-Funktionalität, indem du einfach eine Kommaposition einführst, die angibt, wo der Nachkommateil beginnt.
Die Zahl 123456789012345678901234567890 kann durch Angabe der Info, dass das Komma an Position 20 steht doch als Zahl
12345657890123456789,01234567890 interpretiert werden.
Die Rechenoperationen müssen natürlich entsprechend angepaßt werden.

Wenn du allerdings keine Strings vewrwenden möchtest (Warum nicht?), könntest du natürlich auch ein Array von bytes nehmen und dann bitweise rechnen. Das macht dann wohl noch etwas mehr Arbeit.

Interessant finde ich die Frage, warum du Zahlen mit 30k Ziffern berechnen willst und das mit einer Genauigkeit von 1000 Nachkommastellen?
Mir fällt beim besten Willen keine Fall ein, wo so etwas Sinn macht.
 
Erst mal Danke für deinen Vorschlag.

Darüber habe ich auch schon nachgedacht, mich dann jedoch dagegen entschieden, da das sehr viel aufwand machen würde. Ich verwende bisher die BigInteger-Klasse von Codeproject, mit der klappt das für Integer alles super, nur verstehe ich leider nicht, wie die das intern speichert.
Das läuft irgendwie so: Die Zahl, die man eingibt, wird in Teile gesplittet die in uint reinpassen, also 9-10 Ziffern. Nur hätte ich gedacht, dass die Zahl 12345678910111213 dann nach der 0 gesplittet wird, also 12345678910 und 111213 und jeder Teil in das uint-Array geschrieben wird. Leider macht die Klasse aus der oben genannten Zahl aber 1576189421 und 2874452. Das macht für mich keinen Sinn, ich habe auch schon den Code angeschaut aber komme nicht drauf, wie die das machen.

Daher suche ich einfach eine fertige Klasse, die das schon kann.

Und zur Anwendung:
Ich kann dir so viel sagen, ich will eine Kurve durch viele Punkte legen, sagen wir so 5000 Stück. Um das zu lösen brauche ich eine Matrix, die dann mit dem Gauss-Verfahren gelöst wird. Bei 5000 Punkten hat diese Matrix die Dimension 5000x5001, also 25.005.000 (25 Millionen) Felder. Die Werte der Matrix sind die Potenzen der x-Werte, also wenn mein 1. Punkt (34/0,34) ist, dann steht in der 1. Zeile 1. Spalte 34^4999, in der 2. Spalte 34^4998, usw.
Da siehst du schon dass die Zahlen ganz schön groß werden ;-)
Jetzt kann ich die leider nicht runden oder so, habe das schon versucht, dann wird das Ergebnis nachher zu ungenau. Selbst bei 8 Punkten und der Präzision von double kann man das Ergebnis schon vergessen. Daher müssen mehr Stellen her!
 
Hey Danke, dieses Sine Ding sieht eigentlich genau nach dem aus, was ich brauche, ist nur leider EXTREM langsam...

Ich habe mal einen Test gemacht, mit der BigInteger-Klasse von Codeproject und der BigNumDec-Klasse von diesem Sine Dings 5000^2000 auszurechnen. Beide kommen exakt auf den gleichen Wert, nur braucht BigInteger da 35ms für, wobei BigNumDec 4200ms braucht! Das ist so langsam, das kann ich nicht gebrauchen!

Im Anhang findet ihr das Programm, falls ihr es testen wollt.
 

Anhänge

  • bignum.jpg
    bignum.jpg
    12,7 KB · Aufrufe: 99
  • GaussVerfahren.zip
    24,4 KB · Aufrufe: 45
Die Zahl, die man eingibt, wird in Teile gesplittet die in uint reinpassen, also 9-10 Ziffern. Nur hätte ich gedacht, dass die Zahl 12345678910111213 dann nach der 0 gesplittet wird, also 12345678910 und 111213 und jeder Teil in das uint-Array geschrieben wird. Leider macht die Klasse aus der oben genannten Zahl aber 1576189421 und 2874452. Das macht für mich keinen Sinn, ich habe auch schon den Code angeschaut aber komme nicht drauf, wie die das machen.
Wenn man die Zahlen im Hexadezimalsystem aufschreibt, sieht man es leichter:
Code:
12345678910111213 = 2BDC545DF2BDEDh
          2874452 = 2BDC54h
       1576189421 =       5DF2BDEDh

Und zur Anwendung:
Ich kann dir so viel sagen, ich will eine Kurve durch viele Punkte legen, sagen wir so 5000 Stück. Um das zu lösen brauche ich eine Matrix, die dann mit dem Gauss-Verfahren gelöst wird. Bei 5000 Punkten hat diese Matrix die Dimension 5000x5001, also 25.005.000 (25 Millionen) Felder. Die Werte der Matrix sind die Potenzen der x-Werte, also wenn mein 1. Punkt (34/0,34) ist, dann steht in der 1. Zeile 1. Spalte 34^4999, in der 2. Spalte 34^4998, usw.
Da siehst du schon dass die Zahlen ganz schön groß werden ;-)
Jetzt kann ich die leider nicht runden oder so, habe das schon versucht, dann wird das Ergebnis nachher zu ungenau. Selbst bei 8 Punkten und der Präzision von double kann man das Ergebnis schon vergessen. Daher müssen mehr Stellen her!
Du versuchst hier das Symptom zu bekämpfen und nicht die Ursache. Ich nehme mal an, dass es sich bei der besagten Matrix um die Vandermonde-Matrix handelt und du ein Polynom vom Grad 5000 durch deine Stützpunkte legen willst. Diese Matrix ist nun in der Regel aber extrem schlecht konditioniert, d.h. beim Lösen des Systems schaukeln sich Rundungsfehler immer weiter auf. Abgesehen davon ist der Gauss-Algorithmus zum Lösen eines solch großen Systems eher ungeeignet, da er kubische Laufzeit benötigt. Hier greift man normalerweise auf iterative approximative Lösungsverfahren wie Gauß-Seidel-, Jacobi- oder SOR-Iteration zurück (die aber nicht immer konvergieren, aber das ist eine andere Geschichte). In diesem Fall hilft das aber auch nicht viel, da man der schlecht konditionierten Matrix damit auch nicht entkommt.

Mein Vorschlag wäre daher, ein anderes Interpolationsverfahren zu verwenden, wie z.B. Spline-Interpolation. Vielleicht helfen dir auch die Folien zur Vorlesung Numerisches Programmieren an der TU München weiter.

Grüße, Matthias
 
Hallo,

mit dem .Net Framework 4 gibts nun auch eine (native) BigInteger Implementierung:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;

namespace De.Tutorials.Training
{
    class BigIntegerExample
    {
        static void Main(string[] args)
        {
            Console.WriteLine(factorial(5));
            Console.WriteLine(factorial(16));
            Console.WriteLine(factorial(99));
        }

        static BigInteger factorial(int n)
        {
            BigInteger result = 1;
            for (int i = 1; i <= n; i++)
            {
                result *= i;
            }
            return result;
        }
    }
}

Ausgabe:
Code:
120
20922789888000
933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000

Siehe auch:
http://msdn.microsoft.com/de-de/library/system.numerics.biginteger.aspx

Referenz auf System.Numerics Assembly nicht vergessen.

Gruß Tom
 

Neue Beiträge

Zurück