C#: double zu ungenau, decimal zu klein

benediktibk

Standardgruppe für nicht aktivierte User
#1
Ich bin in die unangenehme Situation gekommen, dass mir in C# ein double zu ungenau und ein decimal zu klein ist. Es geht dabei um einen Algorithmus, der mir die Koeffizienten einer Potenzreihe zum Entwicklungspunkt 0 liefert, die ich dann an der Stelle 1 auswerten muss. Ein möglicher Output wäre das hier (ist aus meinem Code zur Test-Erstellung):
var coefficients = new[]
{
new Complex(-1, 1.6694600439147E-16),
new Complex(1.67974139124394, 0.504426030619388),
new Complex(-0.114101479265145, 0.639980192400492),
new Complex(1.0070656018567, 1.23390998718222),
new Complex(4.47716579955149, 2.07378931269298),
new Complex(13.1100639245265, 2.76508536326347),
new Complex(33.9923988814818, 1.81009331066554),
new Complex(88.4221555238277, -5.37794009669852),
new Complex(242.798088344867, -32.2960729246381),
new Complex(701.18479193071, -118.495662895541),
new Complex(2089.9438132595, -379.147926816592),
new Complex(6368.51500636798, -1146.94332811231),
new Complex(19815.2177126681, -3381.00896328972),
new Complex(62905.1727643245, -9864.07044354301),
new Complex(203126.098913054, -28764.6180671557),
new Complex(664515.281105212, -84376.8776120749),
new Complex(2195349.85010498, -249858.806746953),
new Complex(7308960.04118312, -748045.744209336),
new Complex(24489453.6805216, -2264954.67552451),
new Complex(82499017.8530824, -6933659.79338325),
new Complex(279205898.07835, -21447535.2715492),
new Complex(948717638.734695, -66983956.3152059),
new Complex(3235030793.65458, -211046748.313325),
new Complex(11065942751.3487, -670258582.001958),
new Complex(37961031871.9188, -2144036456.76953),
new Complex(130562729957.63, -6903283349.15794),
new Complex(450131528696.145, -22359251226.9753),
new Complex(1555314579444.13, -72813750664.6764),
new Complex(5384994280710.81, -238302468125.983),
new Complex(18680056512819.2, -783485488703.063),
new Complex(64914465552115.1, -2586838250621.72),
new Complex(225956671082360, -8574508951907.78),
new Complex(787742084261600, -28525357536315.9),
new Complex(2.75028126567498E+15, -95219783202426.4),
new Complex(9.6153919663255E+15, -318860257043707),
new Complex(3.36604212373324E+16, -1.07093379585647E+15),
new Complex(1.17978663006263E+17, -3.6068967938863E+15),
new Complex(4.13990136645768E+17, -1.21798085952344E+16),
new Complex(1.45429534050547E+18, -4.12302371501503E+16),
new Complex(5.11407215883769E+18, -1.39893742001937E+17),
new Complex(1.80015568082651E+19, -4.75697876930109E+17),
new Complex(6.34251144154713E+19, -1.62092314507791E+18),
new Complex(2.2366649570658E+20, -5.53405823233453E+18),
new Complex(7.89425124043963E+20, -1.89291248126283E+19),
new Complex(2.78852396383137E+21, -6.48606874590464E+19),
new Complex(9.85769688141809E+21, -2.22617054453466E+20),
new Complex(3.48738120817103E+22, -7.65289170633181E+20),
new Complex(1.23461757507178E+23, -2.63481304284825E+21),
new Complex(4.37382701455794E+23, -9.08448369839981E+21),
new Complex(1.55051048068301E+24, -3.13652011053964E+22),
};
Wie man unschwer erkennen kann: Da kommen recht fette Zahlen drinnen vor. Damit da überhaupt was sinnvolles heraus kommt verwende ich den Epsilon-Algorithmus von Wynn, der macht ein wenig lustige Magie und tada man bekommt konvergentes Verhalten an der Stelle 1. Soll heißen der Realteil ist etwas in der Richtung von 1.05. Die korrekte Lösung wäre allerdings 1 - j0.1. Ich habe mich da schon ein wenig herum gespielt mit der Anzahl der Koeffizienten und ich bekomme nicht wirklich was genaueres hin. Ebenfalls bereits versucht habe ich bereits den Epsilon-Algorithmus mit komplexen Zahlen basierend auf einem decimal zu implementieren, nur da bekomme ich dann mit bereits viel zu wenigen Koeffizienten Überläufe (intern kommen beim Epsilon-Algorithmus nämlich noch ein paar deutlich größere Werte vor). Damit stehe ich jetzt ein wenig an, weil die 5% Ungenauigkeit sind noch eindeutig zu viel. Was ich bräuchte wäre idealerweise

  • ein genauerer Datentyp als double
  • basierend darauf komplexe Zahlen
  • basierend darauf Matrix-Vektor-Rechnung
  • eine QR-Zerlegung
Ich vermute mal ganz stark, dass ich da nicht alles bekommen kann, bin aber gerne bereit das eine oder andere selber zu implementieren. Ich würde allerdings gerne so weit es geht fertige Bibliotheken verwenden. Die bisher beste Lösung die mir einfällt wäre für den Teil eine Library in C++ zu schreiben, weil mit zum Beispiel dem GCC hätte ich dann einen long double mit 80 Bit bzw. frisch gleich einen __float128. Kombiniert mit Template-Basierten Libraries für das Matrix-Vektor-Zeug müsste ich so mit geringst möglichem Aufwand durchkommen.
Erheblich eleganter wäre es natürlich das direkt in C# zu erledigen. Hat da jemand eine Idee wie das machbar wäre?

mfg benediktibk
 

benediktibk

Standardgruppe für nicht aktivierte User
#2
Mit der Alternative müsste ich dann aber wirklich alles selber machen. Zumindest konnte ich mal keine Matrix-Klasse basierend auf BigInteger finden, erst recht nichts basierend auf komplexen Zahlen mit BigInteger. Genau den Aufwand wollte ich eigentlich vermeiden und für den Teil zu C++ wechseln. Da kann ich dann bei Template-basierten Bibliotheken beliebige Datentypen unterschieben, was vermutlich die leichtere Variante ist.

mfg benediktibk
 
Zuletzt bearbeitet:
Oben