Vollständiges elliptisches Integral 2. Art

Hallo

Ich suche nach einem schnellen Algo, der mit das volständige elliptische Integral 2. Art berechnet. Bisher setze ich auf dieses hier:

	public static double completeEllipticIntegralSecondKind(double k) {
		k *= k;
		if(k > 1.0) {
			return Double.NEGATIVE_INFINITY;
		}
		double sum = 1.0;
		int n = 1;
		double term = 1.0;
		double above = 1.0;
		double below = 2.0;
		double sumOld = 0.0;
		while (sum != sumOld) {
			sumOld = sum;
			term *= above / below;
			sum -= pow(k, n) * pow(term, 2) / above;
			above += 2;
			below += 2;
			n++;
		}
		term = sum * PI_HALFED;
		return term;
	}

aber das dauert mir noch zu lange, erst recht dann, wenn k größer als 0.999 wird. Hat einer eine Idee?

Wolfram Alpha sagt:

π/2 - (π m)/8 - (3 π m^2)/128 - (5 π m^3)/512 - (175 π m^4)/32768 + O(m^5)

(mit m = k²)

Das sieht eigentlich so aus, als ob es schnell konvergiert…

Das sieht auf den ersten Blick auch gar nicht mal schlecht aus… wenn ich nur wüsste, was O(m^5) bedeutet.
Kovergieren tut da, soweit ich das sehe, überhaupt nichts, zumal das (möglicherweise bis auf besagtes O()) alles in einer Zeile geht. Wie genau ist denn das?

Anscheinend brauch ich Wolfram Pro um das Ganze dort zu finden. Aber Registrieren oder irgend etwas erwerben wollte ich für dieses kleine Problem eigentlich nicht.

Ja, das ist leider nur der Anfang der Taylor-Reihe.

Ein kurzer Blick in die OEIS für die Faktoren im Zähler sieht irgendwie vielversprechend aus: “Numerators of coefficients of EllipticE/Pi.”

Vielleicht hilft dir das ja weiter?

Ja, das hilft schon mal weiter. Die Genauigkeit hängt dann wohl davon ab, wieviele Glieder man addiert. Für die Faktoren im Nenner braucht man auf OEIS nur nach der Sequenz 8, 128, 512 und 32768 suchen. Ich werde da mal mit rumexperimentieren.
Danke

Tja schade eigentlich…
Nach 20 Gliedern unterscheidet sich ein Grenzfall (0.9999) von dem ursprünglichen Wert 1.0005145000840605 noch unheimlich von 1.0124863641844215

Für mehr als 16 Glieder reicht ein Double auch schon nicht mehr aus. :frowning:

In der Hoffnung, dass 105 Glieder ausreichen, würde ich als nächsten Schritt aπ/b über BigDecimals zusammengefasst berechnen, damit ich ein einziges Array an Koeffizienten bekomme, die ich nur noch mit m^n (für 0<=n<104) multiplizieren muss. Leider kann ich Dank binomial() mit der Formel
a(n) = 2^(-2 w[n])binomial[2n, n]^2 (-1)^(2n)/(1-2n)
mal so gar nichts anfangen.

Edit: Die 105 Koeffizienten für die Nenner waren schon mal kein Problem.

Edit2: Die 105 Koeffizienten für die Zähler funktionieren nun auch, aber leider leider konvergiert auch dieses immer langsamer, je größer n wird. Nach den 105 Gliedern ergibt k=0,9996 1.0035864106410735 obwohl 1.0017808456277624 heraus kommen sollte.

Optimal wäre ein Algo, der auf den Bereich 0,9996<k<1.0 optimiert ist. k=1.0 ergibt 1.0 und k>1.0 ergibt -Infinity.

Die Taylorreihe kann man auch bei x= 1 entwickeln, Wolfram Alpha spuckt dafür dieses Monster aus:

E(1|m) + (x - 1) sqrt(1 - m sin^2(1)) - ((x - 1)^2 (m sin(2)))/(4 sqrt(1 - m sin^2(1))) - ((x - 1)^3 (m (m sin^4(1) + cos(2))))/(6 (1 - m sin^2(1))^(3/2)) + (m (x - 1)^4 sin(1) cos(1) (m^2 sin^4(1) + m (cos(2) - 4) + 4))/(24 (1 - m sin^2(1))^(5/2)) + (m (x - 1)^5 sqrt(1 - m sin^2(1)) (2 m^3 sin^8(1) - m^2 sin^2(1) (17 + 6 cos(2) + cos(4)) - m (-7 + 12 cos(2) + cos(4)) + 8 cos(2)))/(15 (m (cos(2) - 1) + 2)^4) + O((x - 1)^6)

Komisch, dass er die sin(1)-Werte nicht vereinfacht. E(1|m) müsste 1 sein.

Das ist nur für das normale Integral. Beim vollständigen bleibt der Parameter x unangetastet auf PI/2.
Ich denke mal, es läuft darauf hinaus, dass ich bei Werten zwischen 0,9996 und 1 auf die Annäherung durch ein Polynom zurückgreifen muss.

Yay… Man hab ich ein Glück…


	public static double completeEllipticIntegralSecondKind(double k) {
		if (k > 1.0) {
			return Double.NEGATIVE_INFINITY;
		}
		if (k == 1.0) {
			return 1.0;
		}
		double k1 = k;
		k *= k;
		double k2 = sqrt(1 - k);
		if(k1 > k2) {
			double kk1 = completeEllipticIntegralFirstKind(k1);
			double kk2 = completeEllipticIntegralFirstKind(k2);
			double ek1 = completeEllipticIntegralSecondKind(k2);
			double ek2 = (PI_HALFED + kk1 * kk2 - kk1 * ek1) / kk2;
			return ek2;
		}
		double sum = 1.0;
		int n = 1;
		double term = 1.0;
		int above = 1;
		int below = 2;
		double sumOld = 0.0;
		while (sum != sumOld && n > 0) {
			sumOld = sum;
			term *= above / (double) below;
			sum -= pow(k, n) * pow(term, 2) / above;
			above += 2;
			below += 2;
			n++;
		}
		sum *= PI_HALFED;
		return sum;
	}

	public static double completeEllipticIntegralFirstKind(double k) {
		return PI_HALFED / agm(1, sqrt(1 - k * k));
	}

	public static double agm(double a, double g) {
		if(a == g) {
			return a;
		}
		if(g == 0) {
			return 0;
		}
		double a1 = 0.5 * (a + g);
		double g1 = sqrt(a * g);
		if(a == a1 && g == g1) {
			return (a + g) / 2.0;
		}
		return agm(a1, g1);
	}

Das Intergal 1. Art geht dank dem Arithmetisch-geometrisches Mittel immer recht schnell und dank der Legendres Relation, braucht man nur noch abzuwägen, wann k > √(1-k²) ist. Dann berechnet man das kleinere Intergral 2. Art und berechnet daraus das Größere. Das ist zwar auf den letzten beiden Nachkommastellen ungenau, aber was solls. Ich will gar nicht wissen, wie ungenau die polynimiale Annäherung gewesen wär.

Nur zur Info, wenn es einer noch mal braucht.