way valueof round places convert big best java double bigdecimal complex-numbers

valueof - Convertir doble a BigDecimal en Java



double to bigdecimal java (3)

(1) La integración utiliza adaptQuad, comenzando con un intervalo [0,10]. Para z = a + ib con valores cada vez mayores de a y b = 0, el integrando es una función cada vez más oscilante, con el número de ceros en [0,5] solo proporcional a a y aumentando a 43 para z = 100.

Por lo tanto, comenzar la aproximación con un intervalo que incluya uno o más ceros es arriesgado, ya que el programa publicado muestra con bastante claridad. Para z = 100, el integrando es 0, -2.08E-78 y 7.12E-115 en 0, 5 y 10, respectivamente. Por lo tanto, comparar el resultado de la fórmula de Simpson con 1E-20 devuelve verdadero, y el resultado es absolutamente incorrecto.

(2) El cálculo en el método AbelPlana involucra dos números complejos, C1 y C2. Para z = a + 0i, son reales, y la siguiente tabla muestra sus valores para varios valores de a:

a C1 C2 10 5.689E1 1.024E3 20 2.759E4 1.048E6 30 1.851E7 1.073E9 40 1.409E10 1.099E12 60 9.770E15 1.152E18 100 6.402E27 1.267E30

Ahora sabemos que los valores de ζ (a + 0i) disminuyen hacia 1 para aumentar a. Es claramente imposible que dos valores superiores a 1E15 produzcan un resultado significativo cerca de uno cuando se restan uno del otro.

La tabla también sugiere que para obtener un buen resultado de ζ (a + 0i) mediante el uso de este algoritmo, C1 y C2 * I (I es la integral) deben calcularse con una precisión de aproximadamente 45 dígitos significativos. (La matemática de precisión arbitraria no evita el escollo descrito en (1)).

(3) Tenga en cuenta que al usar una biblioteca con precisión arbitraria, los valores como E y PI deben proporcionarse con una precisión mejor que la que pueden ofrecer los valores dobles en java.lang.Math.

Editar (25.5.11) tiene tantos ceros en [0,10] como (25.5.12). El cálculo en 0 es complicado, pero no es una singularidad. Evita el problema (2).

Escribí un programa Java que calcula valores para la función Zeta de Riemann . Dentro del programa, hice una biblioteca para calcular las funciones complejas necesarias, como atan, cos, etc. Se puede acceder a todo dentro de ambos programas a través de los tipos de datos double y BigDecimal . Esto crea problemas importantes al evaluar valores grandes para la función Zeta.

La aproximación numérica para las referencias de la función Zeta.

La evaluación directa de esta aproximación a valores altos crea problemas cuando s tiene una forma compleja grande, como s = (230+30i) . Estoy muy agradecido de obtener información sobre esto here . La evaluación de S2.minus(S1) crea errores porque escribí algo incorrecto en el método adaptiveQuad .

Como ejemplo, Zeta(2+3i) través de este programa genera

Calculation of the Riemann Zeta Function in the form Zeta(s) = a + ib. Enter the value of [a] inside the Riemann Zeta Function: 2 Enter the value of [b] inside the Riemann Zeta Function: 3 The value for Zeta(s) is 7.980219851133409E-1 - 1.137443081631288E-1*i Total time taken is 0.469 seconds.

Lo cual es correct .

Zeta(100+0i) genera

Calculation of the Riemann Zeta Function in the form Zeta(s) = a + ib. Enter the value of [a] inside the Riemann Zeta Function: 100 Enter the value of [b] inside the Riemann Zeta Function: 0 The value for Zeta(s) is 1.000000000153236E0 Total time taken is 0.672 seconds.

Lo que también es correcto en comparación con Wolfram . El problema se debe a algo dentro del método etiquetado adaptiveQuad .

Zeta(230+30i) genera

Calculation of the Riemann Zeta Function in the form Zeta(s) = a + ib. Enter the value of [a] inside the Riemann Zeta Function: 230 Enter the value of [b] inside the Riemann Zeta Function: 30 The value for Zeta(s) is 0.999999999999093108519845391615339162047254997503854254342793916541606842461539820124897870147977114468145672577664412128509813042591501204781683860384769321084473925620572315416715721728082468412672467499199310913504362891199180150973087384370909918493750428733837552915328069343498987460727711606978118652477860450744628906250 - 38.005428584222228490409289204403133867487950535704812764806874887805043029499897666636162309572126423385487374863788363786029170239477119910868455777891701471328505006916099918492113970510619110472506796418206225648616641319533972054228283869713393805956289770456519729094756021581247296126093715429306030273437500E-15*i Total time taken is 1.746 seconds.

La parte imaginaria está un poco apagada en comparación con Wolfram .

El algoritmo para evaluar la integral se conoce como cuadratura adaptativa y here se encuentra una implementación double Java. El método cuádruple adaptativo aplica lo siguiente

// adaptive quadrature public static double adaptive(double a, double b) { double h = b - a; double c = (a + b) / 2.0; double d = (a + c) / 2.0; double e = (b + c) / 2.0; double Q1 = h/6 * (f(a) + 4*f(c) + f(b)); double Q2 = h/12 * (f(a) + 4*f(d) + 2*f(c) + 4*f(e) + f(b)); if (Math.abs(Q2 - Q1) <= EPSILON) return Q2 + (Q2 - Q1) / 15; else return adaptive(a, c) + adaptive(c, b); }

Aquí está mi cuarto intento de escribir el programa.

/************************************************************************** ** ** Abel-Plana Formula for the Zeta Function ** ************************************************************************** ** Axion004 ** 08/16/2015 ** ** This program computes the value for Zeta(z) using a definite integral ** approximation through the Abel-Plana formula. The Abel-Plana formula ** can be shown to approximate the value for Zeta(s) through a definite ** integral. The integral approximation is handled through the Composite ** Simpson''s Rule known as Adaptive Quadrature. **************************************************************************/ import java.util.*; import java.math.*; public class AbelMain5 extends Complex { private static MathContext MC = new MathContext(512, RoundingMode.HALF_EVEN); public static void main(String[] args) { AbelMain(); } // Main method public static void AbelMain() { double re = 0, im = 0; double start, stop, totalTime; Scanner scan = new Scanner(System.in); System.out.println("Calculation of the Riemann Zeta " + "Function in the form Zeta(s) = a + ib."); System.out.println(); System.out.print("Enter the value of [a] inside the Riemann Zeta " + "Function: "); try { re = scan.nextDouble(); } catch (Exception e) { System.out.println("Please enter a valid number for a."); } System.out.print("Enter the value of [b] inside the Riemann Zeta " + "Function: "); try { im = scan.nextDouble(); } catch (Exception e) { System.out.println("Please enter a valid number for b."); } start = System.currentTimeMillis(); Complex z = new Complex(new BigDecimal(re), new BigDecimal(im)); System.out.println("The value for Zeta(s) is " + AbelPlana(z)); stop = System.currentTimeMillis(); totalTime = (double) (stop-start) / 1000.0; System.out.println("Total time taken is " + totalTime + " seconds."); } /** * The definite integral for Zeta(z) in the Abel-Plana formula. * <br> Numerator = Sin(z * arctan(t)) * <br> Denominator = (1 + t^2)^(z/2) * (e^(2*pi*t) - 1) * @param t - the value of t passed into the integrand. * @param z - The complex value of z = a + i*b * @return the value of the complex function. */ public static Complex f(double t, Complex z) { Complex num = (z.multiply(Math.atan(t))).sin(); Complex D1 = new Complex(1 + t*t).pow(z.divide(TWO)); Complex D2 = new Complex(Math.pow(Math.E, 2.0*Math.PI*t) - 1.0); Complex den = D1.multiply(D2); return num.divide(den, MC); } /** * Adaptive quadrature - See http://www.mathworks.com/moler/quad.pdf * @param a - the lower bound of integration. * @param b - the upper bound of integration. * @param z - The complex value of z = a + i*b * @return the approximate numerical value of the integral. */ public static Complex adaptiveQuad(double a, double b, Complex z) { double EPSILON = 1E-10; double step = b - a; double c = (a + b) / 2.0; double d = (a + c) / 2.0; double e = (b + c) / 2.0; Complex S1 = (f(a, z).add(f(c, z).multiply(FOUR)).add(f(b, z))). multiply(step / 6.0); Complex S2 = (f(a, z).add(f(d, z).multiply(FOUR)).add(f(c, z).multiply (TWO)).add(f(e, z).multiply(FOUR)).add(f(b, z))).multiply (step / 12.0); Complex result = (S2.subtract(S1)).divide(FIFTEEN, MC); if(S2.subtract(S1).mod() <= EPSILON) return S2.add(result); else return adaptiveQuad(a, c, z).add(adaptiveQuad(c, b, z)); } /** * The definite integral for Zeta(z) in the Abel-Plana formula. * <br> value = 1/2 + 1/(z-1) + 2 * Integral * @param z - The complex value of z = a + i*b * @return the value of Zeta(z) through value and the * quadrature approximation. */ public static Complex AbelPlana(Complex z) { Complex C1 = ONEHALF.add(ONE.divide(z.subtract(ONE), MC)); Complex C2 = TWO.multiply(adaptiveQuad(1E-16, 100.0, z)); if ( z.real().doubleValue() == 0 && z.imag().doubleValue() == 0) return new Complex(0.0, 0.0); else return C1.add(C2); } }

Números complejos ( BigDecimal )

/************************************************************************** ** ** Complex Numbers ** ************************************************************************** ** Axion004 ** 08/20/2015 ** ** This class is necessary as a helper class for the calculation of ** imaginary numbers. The calculation of Zeta(z) inside AbelMain is in ** the form of z = a + i*b. **************************************************************************/ import java.math.BigDecimal; import java.math.MathContext; import java.text.DecimalFormat; import java.text.NumberFormat; public class Complex extends Object{ private BigDecimal re; private BigDecimal im; /** BigDecimal constant for zero */ final static Complex ZERO = new Complex(BigDecimal.ZERO) ; /** BigDecimal constant for one half */ final static Complex ONEHALF = new Complex(new BigDecimal(0.5)); /** BigDecimal constant for one */ final static Complex ONE = new Complex(BigDecimal.ONE); /** BigDecimal constant for two */ final static Complex TWO = new Complex(new BigDecimal(2.0)); /** BigDecimal constant for four */ final static Complex FOUR = new Complex(new BigDecimal(4.0)) ; /** BigDecimal constant for fifteen */ final static Complex FIFTEEN = new Complex(new BigDecimal(15.0)) ; /** Default constructor equivalent to zero */ public Complex() { re = BigDecimal.ZERO; im = BigDecimal.ZERO; } /** Constructor with real part only @param x Real part, BigDecimal */ public Complex(BigDecimal x) { re = x; im = BigDecimal.ZERO; } /** Constructor with real part only @param x Real part, double */ public Complex(double x) { re = new BigDecimal(x); im = BigDecimal.ZERO; } /** Constructor with real and imaginary parts in double format. @param x Real part @param y Imaginary part */ public Complex(double x, double y) { re= new BigDecimal(x); im= new BigDecimal(y); } /** Constructor for the complex number z = a + i*b @param re Real part @param im Imaginary part */ public Complex (BigDecimal re, BigDecimal im) { this.re = re; this.im = im; } /** Real part of the Complex number @return Re[z] where z = a + i*b. */ public BigDecimal real() { return re; } /** Imaginary part of the Complex number @return Im[z] where z = a + i*b. */ public BigDecimal imag() { return im; } /** Complex conjugate of the Complex number in which the conjugate of z is z-bar. @return z-bar where z = a + i*b and z-bar = a - i*b */ public Complex conjugate() { return new Complex(re, im.negate()); } /** * Returns the sum of this and the parameter. @param augend the number to add @param mc the context to use @return this + augend */ public Complex add(Complex augend,MathContext mc) { //(a+bi)+(c+di) = (a + c) + (b + d)i return new Complex( re.add(augend.re,mc), im.add(augend.im,mc)); } /** Equivalent to add(augend, MathContext.UNLIMITED) @param augend the number to add @return this + augend */ public Complex add(Complex augend) { return add(augend, MathContext.UNLIMITED); } /** Addition of Complex number and a double. @param d is the number to add. @return z+d where z = a+i*b and d = double */ public Complex add(double d){ BigDecimal augend = new BigDecimal(d); return new Complex(this.re.add(augend, MathContext.UNLIMITED), this.im); } /** * Returns the difference of this and the parameter. @param subtrahend the number to subtract @param mc the context to use @return this - subtrahend */ public Complex subtract(Complex subtrahend, MathContext mc) { //(a+bi)-(c+di) = (a - c) + (b - d)i return new Complex( re.subtract(subtrahend.re,mc), im.subtract(subtrahend.im,mc)); } /** * Equivalent to subtract(subtrahend, MathContext.UNLIMITED) @param subtrahend the number to subtract @return this - subtrahend */ public Complex subtract(Complex subtrahend) { return subtract(subtrahend,MathContext.UNLIMITED); } /** Subtraction of Complex number and a double. @param d is the number to subtract. @return z-d where z = a+i*b and d = double */ public Complex subtract(double d){ BigDecimal subtrahend = new BigDecimal(d); return new Complex(this.re.subtract(subtrahend, MathContext.UNLIMITED), this.im); } /** * Returns the product of this and the parameter. @param multiplicand the number to multiply by @param mc the context to use @return this * multiplicand */ public Complex multiply(Complex multiplicand, MathContext mc) { //(a+bi)(c+di) = (ac - bd) + (ad + bc)i return new Complex( re.multiply(multiplicand.re,mc).subtract(im.multiply (multiplicand.im,mc),mc), re.multiply(multiplicand.im,mc).add(im.multiply (multiplicand.re,mc),mc)); } /** Equivalent to multiply(multiplicand, MathContext.UNLIMITED) @param multiplicand the number to multiply by @return this * multiplicand */ public Complex multiply(Complex multiplicand) { return multiply(multiplicand,MathContext.UNLIMITED); } /** Complex multiplication by a double. @param d is the double to multiply by. @return z*d where z = a+i*b and d = double */ public Complex multiply(double d){ BigDecimal multiplicand = new BigDecimal(d); return new Complex(this.re.multiply(multiplicand, MathContext.UNLIMITED) ,this.im.multiply(multiplicand, MathContext.UNLIMITED)); } /** Modulus of a Complex number or the distance from the origin in * the polar coordinate plane. @return |z| where z = a + i*b. */ public double mod() { if ( re.doubleValue() != 0.0 || im.doubleValue() != 0.0) return Math.sqrt(re.multiply(re).add(im.multiply(im)) .doubleValue()); else return 0.0; } /** * Modulus of a Complex number squared * @param z = a + i*b * @return |z|^2 where z = a + i*b */ public double abs(Complex z) { double doubleRe = re.doubleValue(); double doubleIm = im.doubleValue(); return doubleRe * doubleRe + doubleIm * doubleIm; } public Complex divide(Complex divisor) { return divide(divisor,MathContext.UNLIMITED); } /** * The absolute value squared. * @return The sum of the squares of real and imaginary parts. * This is the square of Complex.abs() . */ public BigDecimal norm() { return re.multiply(re).add(im.multiply(im)) ; } /** * The absolute value of a BigDecimal. * @param mc amount of precision * @return BigDecimal.abs() */ public BigDecimal abs(MathContext mc) { return BigDecimalMath.sqrt(norm(),mc) ; } /** The inverse of the the Complex number. @param mc amount of precision @return 1/this */ public Complex inverse(MathContext mc) { final BigDecimal hyp = norm() ; /* 1/(x+iy)= (x-iy)/(x^2+y^2 */ return new Complex( re.divide(hyp,mc), im.divide(hyp,mc) .negate() ) ; } /** Divide through another BigComplex number. @param oth the other complex number @param mc amount of precision @return this/other */ public Complex divide(Complex oth, MathContext mc) { /* implementation: (x+iy)/(a+ib)= (x+iy)* 1/(a+ib) */ return multiply(oth.inverse(mc),mc) ; } /** Division of Complex number by a double. @param d is the double to divide @return new Complex number z/d where z = a+i*b */ public Complex divide(double d){ BigDecimal divisor = new BigDecimal(d); return new Complex(this.re.divide(divisor, MathContext.UNLIMITED), this.im.divide(divisor, MathContext.UNLIMITED)); } /** Exponential of a complex number (z is unchanged). <br> e^(a+i*b) = e^a * e^(i*b) = e^a * (cos(b) + i*sin(b)) @return exp(z) where z = a+i*b */ public Complex exp () { return new Complex(Math.exp(re.doubleValue()) * Math.cos(im. doubleValue()), Math.exp(re.doubleValue()) * Math.sin(im.doubleValue())); } /** The Argument of a Complex number or the angle in radians with respect to polar coordinates. <br> Tan(theta) = b / a, theta = Arctan(b / a) <br> a is the real part on the horizontal axis <br> b is the imaginary part of the vertical axis @return arg(z) where z = a+i*b. */ public double arg() { return Math.atan2(im.doubleValue(), re.doubleValue()); } /** The log or principal branch of a Complex number (z is unchanged). <br> Log(a+i*b) = ln|a+i*b| + i*Arg(z) = ln(sqrt(a^2+b^2)) * + i*Arg(z) = ln (mod(z)) + i*Arctan(b/a) @return log(z) where z = a+i*b */ public Complex log() { return new Complex(Math.log(this.mod()), this.arg()); } /** The square root of a Complex number (z is unchanged). Returns the principal branch of the square root. <br> z = e^(i*theta) = r*cos(theta) + i*r*sin(theta) <br> r = sqrt(a^2+b^2) <br> cos(theta) = a / r, sin(theta) = b / r <br> By De Moivre''s Theorem, sqrt(z) = sqrt(a+i*b) = * e^(i*theta / 2) = r(cos(theta/2) + i*sin(theta/2)) @return sqrt(z) where z = a+i*b */ public Complex sqrt() { double r = this.mod(); double halfTheta = this.arg() / 2; return new Complex(Math.sqrt(r) * Math.cos(halfTheta), Math.sqrt(r) * Math.sin(halfTheta)); } /** The real cosh function for Complex numbers. <br> cosh(theta) = (e^(theta) + e^(-theta)) / 2 @return cosh(theta) */ private double cosh(double theta) { return (Math.exp(theta) + Math.exp(-theta)) / 2; } /** The real sinh function for Complex numbers. <br> sinh(theta) = (e^(theta) - e^(-theta)) / 2 @return sinh(theta) */ private double sinh(double theta) { return (Math.exp(theta) - Math.exp(-theta)) / 2; } /** The sin function for the Complex number (z is unchanged). <br> sin(a+i*b) = cosh(b)*sin(a) + i*(sinh(b)*cos(a)) @return sin(z) where z = a+i*b */ public Complex sin() { return new Complex(cosh(im.doubleValue()) * Math.sin(re.doubleValue()), sinh(im.doubleValue())* Math.cos(re.doubleValue())); } /** The cos function for the Complex number (z is unchanged). <br> cos(a +i*b) = cosh(b)*cos(a) + i*(-sinh(b)*sin(a)) @return cos(z) where z = a+i*b */ public Complex cos() { return new Complex(cosh(im.doubleValue()) * Math.cos(re.doubleValue()), -sinh(im.doubleValue()) * Math.sin(re.doubleValue())); } /** The hyperbolic sin of the Complex number (z is unchanged). <br> sinh(a+i*b) = sinh(a)*cos(b) + i*(cosh(a)*sin(b)) @return sinh(z) where z = a+i*b */ public Complex sinh() { return new Complex(sinh(re.doubleValue()) * Math.cos(im.doubleValue()), cosh(re.doubleValue()) * Math.sin(im.doubleValue())); } /** The hyperbolic cosine of the Complex number (z is unchanged). <br> cosh(a+i*b) = cosh(a)*cos(b) + i*(sinh(a)*sin(b)) @return cosh(z) where z = a+i*b */ public Complex cosh() { return new Complex(cosh(re.doubleValue()) *Math.cos(im.doubleValue()), sinh(re.doubleValue()) * Math.sin(im.doubleValue())); } /** The tan of the Complex number (z is unchanged). <br> tan (a+i*b) = sin(a+i*b) / cos(a+i*b) @return tan(z) where z = a+i*b */ public Complex tan() { return (this.sin()).divide(this.cos()); } /** The arctan of the Complex number (z is unchanged). <br> tan^(-1)(a+i*b) = 1/2 i*(log(1-i*(a+b*i))-log(1+i*(a+b*i))) = <br> -1/2 i*(log(i*a - b+1)-log(-i*a + b+1)) @return arctan(z) where z = a+i*b */ public Complex atan(){ Complex ima = new Complex(0.0,-1.0); //multiply by negative i Complex num = new Complex(this.re.doubleValue(),this.im.doubleValue() -1.0); Complex den = new Complex(this.re.negate().doubleValue(),this.im .negate().doubleValue()-1.0); Complex two = new Complex(2.0, 0.0); // divide by 2 return ima.multiply(num.divide(den).log()).divide(two); } /** * The Math.pow equivalent of two Complex numbers. * @param z - the complex base in the form z = a + i*b * @return z^y where z = a + i*b and y = c + i*d */ public Complex pow(Complex z){ Complex a = z.multiply(this.log(), MathContext.UNLIMITED); return a.exp(); } /** * The Math.pow equivalent of a Complex number to the power * of a double. * @param d - the double to be taken as the power. * @return z^d where z = a + i*b and d = double */ public Complex pow(double d){ Complex a=(this.log()).multiply(d); return a.exp(); } /** Override the .toString() method to generate complex numbers, the * string representation is now a literal Complex number. @return a+i*b, a-i*b, a, or i*b as desired. */ public String toString() { NumberFormat formatter = new DecimalFormat(); formatter = new DecimalFormat("#.###############E0"); if (re.doubleValue() != 0.0 && im.doubleValue() > 0.0) { return formatter.format(re) + " + " + formatter.format(im) +"*i"; } if (re.doubleValue() !=0.0 && im.doubleValue() < 0.0) { return formatter.format(re) + " - "+ formatter.format(im.negate()) + "*i"; } if (im.doubleValue() == 0.0) { return formatter.format(re); } if (re.doubleValue() == 0.0) { return formatter.format(im) + "*i"; } return formatter.format(re) + " + i*" + formatter.format(im); } }

Estoy revisando la respuesta a continuación.

Un problema puede ser debido a

Complex num = (z.multiply(Math.atan(t))).sin(); Complex D1 = new Complex(1 + t*t).pow(z.divide(TWO)); Complex D2 = new Complex(Math.pow(Math.E, 2.0*Math.PI*t) - 1.0); Complex den = D1.multiply(D2, MathContext.UNLIMITED);

No estoy aplicando BigDecimal.pow(BigDecimal) . Aunque, no creo que este sea el problema directo que hace que la aritmética de punto flotante cree diferencias.

Edición : Probé una nueva aproximación integral de la función Zeta. En última instancia, desarrollaré un nuevo método para calcular BigDecimal.pow(BigDecimal) .


Advertencia, estoy de acuerdo con todos los comentarios en la respuesta de @laune , pero tengo la impresión de que quizás desee continuar con esto de todos modos. Asegúrese especialmente de que realmente entiende 1) y lo que eso significa para usted: es muy fácil hacer muchos cálculos pesados ​​para producir resultados sin sentido.

Funciones de punto flotante de precisión arbitraria en Java

Para reiterar un poco, creo que su problema realmente está relacionado con las matemáticas y el método numérico que ha elegido, pero aquí hay una implementación que utiliza la biblioteca Apfloat . Le insto encarecidamente a que utilice la biblioteca de precisión arbitraria (o una similar) ya preparada, ya que evita cualquier necesidad de que "haga rodar sus propias" funciones matemáticas de precisión arbitraria (como pow , exp , sin , atan , etc.). Tu dices

En última instancia, desarrollaré un nuevo método para calcular BigDecimal.pow (BigDecimal)

Es muy difícil hacerlo bien.

También debe observar la precisión de sus constantes; tenga en cuenta que utilizo una implementación de ejemplo de Apfloat para calcular PI a un gran número (¡para alguna definición de grande!) De sig figs. Estoy hasta cierto punto confiando en que la biblioteca de Apfloat usa valores adecuadamente precisos para e en la exponenciación: la fuente está disponible si desea verificar.

Diferentes formulaciones integrales para calcular zeta.

Coloca tres métodos diferentes de integración en una de sus ediciones:
El que está etiquetado como 25.5.12 es el que tiene actualmente en la pregunta y (aunque eso se puede calcular fácilmente en cero), es difícil trabajar con él debido a 2) en la respuesta de @laune . Implementé 25.5.12 como integrand1() en el código. Le insto a que lo trace con un rango de t para diferentes s = a + 0i y entienda cómo se comporta. O mira las tramas en el artículo zeta sobre el mundo matemático de Wolfram. El etiquetado 25.5.11 implementé a través de integrand2() y el código en la configuración que publico a continuación.

Código

Aunque estoy un poco reacio a publicar códigos que sin duda encontrarán resultados incorrectos en algunas configuraciones debido a todas las cosas anteriores, he codificado lo que se intenta hacer a continuación, utilizando objetos de punto flotante de precisión arbitraria para las variables.

Si desea cambiar la formulación que utiliza (p. Ej., Del 25.5.11 al 25.5.12), puede cambiar a qué función integra la función de envoltorio f() devuelve o, mejor aún, cambiar adaptiveQuad para tomar un método integrando arbitrario envuelto en una class con una interfaz ... También tendrá que modificar la aritmética en findZeta() si desea usar una de las otras formulaciones integrales.

Juega con las constantes al comienzo de tu corazón. No he probado muchas combinaciones, ya que creo que los problemas matemáticos aquí anulan los de programación.

Lo he dejado configurado para hacer 2+3i en aproximadamente 2000 llamadas al método de cuadratura adaptativa y hacer coincidir los primeros 15 dígitos del valor de Wolfram.

He probado que todavía funciona con PRECISION = 120l y EPSILON=1e-15 . El programa coincide con Wolfram alfa en las primeras 18 cifras más o menos significativas para los tres casos de prueba que proporciona. El último ( 230+30i ) toma mucho tiempo, incluso en una computadora rápida: llama a la función integrand unas 100,000 veces más. Tenga en cuenta que utilizo 40 para el valor de INFINITY en la integral, no muy alto, pero los valores más altos muestran el problema 1) como ya se mencionó ...

NB: Esto no es rápido (medirá en minutos u horas, no en segundos, pero solo lo hará si desea aceptar ese 10 ^ -15 ~ = 10 ^ -70 como lo haría la mayoría de las personas). Le dará algunos dígitos que coinciden con Wolfram Alpha;) Es posible que desee tomar PRECISION hasta aproximadamente 20 , INFINITY hasta 10 y EPSILON hasta 1e-10 para verificar algunos resultados con una pequeña s primero ... Lo he dejado en algunos imprimiendo así que te dice que cada 100 veces se llama adaptiveQuad para mayor comodidad.

Reiteración Por muy buena que sea su precisión, no va a superar las características matemáticas de las funciones involucradas en esta forma de calcular zeta. Dudo mucho que así sea como lo hace Wolfram alpha, por ejemplo. Busque los métodos de suma de series si desea métodos más manejables.

import java.io.PrintWriter; import org.apfloat.ApcomplexMath; import org.apfloat.Apcomplex; import org.apfloat.Apfloat; import org.apfloat.samples.Pi; public class ZetaFinder { //Number of sig figs accuracy. Note that infinite should be reserved private static long PRECISION = 40l; // Convergence criterion for integration static Apfloat EPSILON = new Apfloat("1e-15",PRECISION); //Value of PI - enhanced using Apfloat library sample calculation of Pi in constructor, //Fast enough that we don''t need to hard code the value in. //You could code hard value in for perf enhancement static Apfloat PI = null; //new Apfloat("3.14159"); //Integration limits - I found too high a value for "infinity" causes integration //to terminate on first iteration. Plot the integrand to see why... static Apfloat INFINITE_LIMIT = new Apfloat("40",PRECISION); static Apfloat ZERO_LIMIT = new Apfloat("1e-16",PRECISION); //You can use zero for the 25.5.12 static Apfloat one = new Apfloat("1",PRECISION); static Apfloat two = new Apfloat("2",PRECISION); static Apfloat four = new Apfloat("4",PRECISION); static Apfloat six = new Apfloat("6",PRECISION); static Apfloat twelve = new Apfloat("12",PRECISION); static Apfloat fifteen = new Apfloat("15",PRECISION); static int counter = 0; Apcomplex s = null; public ZetaFinder(Apcomplex s) { this.s = s; Pi.setOut(new PrintWriter(System.out, true)); Pi.setErr(new PrintWriter(System.err, true)); PI = (new Pi.RamanujanPiCalculator(PRECISION+10, 10)).execute(); //Get Pi to a higher precision than integer consts System.out.println("Created a Zeta Finder based on Abel-Plana for s="+s.toString() + " using PI="+PI.toString()); } public static void main(String[] args) { Apfloat re = new Apfloat("2", PRECISION); Apfloat im = new Apfloat("3", PRECISION); Apcomplex s = new Apcomplex(re,im); ZetaFinder finder = new ZetaFinder(s); System.out.println(finder.findZeta()); } private Apcomplex findZeta() { Apcomplex retval = null; //Method currently in question (a.k.a. 25.5.12) //Apcomplex mult = ApcomplexMath.pow(two, this.s); //Apcomplex firstterm = (ApcomplexMath.pow(two, (this.s.add(one.negate())))).divide(this.s.add(one.negate())); //Easier integrand method (a.k.a. 25.5.11) Apcomplex mult = two; Apcomplex firstterm = (one.divide(two)).add(one.divide(this.s.add(one.negate()))); Apfloat limita = ZERO_LIMIT;//Apfloat.ZERO; Apfloat limitb = INFINITE_LIMIT; System.out.println("Trying to integrate between " + limita.toString() + " and " + limitb.toString()); Apcomplex integral = adaptiveQuad(limita, limitb); retval = firstterm.add((mult.multiply(integral))); return retval; } private Apcomplex adaptiveQuad(Apfloat a, Apfloat b) { //if (counter % 100 == 0) { System.out.println("In here for the " + counter + "th time"); } counter++; Apfloat h = b.add(a.negate()); Apfloat c = (a.add(b)).divide(two); Apfloat d = (a.add(c)).divide(two); Apfloat e = (b.add(c)).divide(two); Apcomplex Q1 = (h.divide(six)).multiply(f(a).add(four.multiply(f(c))).add(f(b))); Apcomplex Q2 = (h.divide(twelve)).multiply(f(a).add(four.multiply(f(d))).add(two.multiply(f(c))).add(four.multiply(f(e))).add(f(b))); if (ApcomplexMath.abs(Q2.add(Q1.negate())).compareTo(EPSILON) < 0) { System.out.println("Returning"); return Q2.add((Q2.add(Q1.negate())).divide(fifteen)); } else { System.out.println("Recursing with intervals "+a+" to " + c + " and " + c + " to " +d); return adaptiveQuad(a, c).add(adaptiveQuad(c, b)); } } private Apcomplex f(Apfloat x) { return integrand2(x); } /* * Simple test integrand (z^2) * * Can test implementation by asserting that the adaptiveQuad * with this function evaluates to z^3 / 3 */ private Apcomplex integrandTest(Apfloat t) { return ApcomplexMath.pow(t, two); } /* * Abel-Plana formulation integrand */ private Apcomplex integrand1(Apfloat t) { Apcomplex numerator = ApcomplexMath.sin(this.s.multiply(ApcomplexMath.atan(t))); Apcomplex bottomlinefirstbr = one.add(ApcomplexMath.pow(t, two)); Apcomplex D1 = ApcomplexMath.pow(bottomlinefirstbr, this.s.divide(two)); Apcomplex D2 = (ApcomplexMath.exp(PI.multiply(t))).add(one); Apcomplex denominator = D1.multiply(D2); Apcomplex retval = numerator.divide(denominator); //System.out.println("Integrand evaluated at "+t+ " is "+retval); return retval; } /* * Abel-Plana formulation integrand 25.5.11 */ private Apcomplex integrand2(Apfloat t) { Apcomplex numerator = ApcomplexMath.sin(this.s.multiply(ApcomplexMath.atan(t))); Apcomplex bottomlinefirstbr = one.add(ApcomplexMath.pow(t, two)); Apcomplex D1 = ApcomplexMath.pow(bottomlinefirstbr, this.s.divide(two)); Apcomplex D2 = ApcomplexMath.exp(two.multiply(PI.multiply(t))).add(one.negate()); Apcomplex denominator = D1.multiply(D2); Apcomplex retval = numerator.divide(denominator); //System.out.println("Integrand evaluated at "+t+ " is "+retval); return retval; } }

Una nota sobre "corrección"

Tenga en cuenta que en su respuesta, usted está llamando a zeta(2+3i) y zeta(100) "correctas" en comparación con Wolfram cuando muestran errores de ~ 1e-10 y ~ 1e-9 respectivamente (difieren en la décima y novena posición). lugar decimal), pero le preocupa zeta(230+30i) porque muestra un error de orden 10e-14 en el componente imaginario ( 38e-15 vs 5e-70 , ambos muy cerca de cero). Entonces, en algunos sentidos, el que está llamando "incorrecto" está más cerca del valor de Wolfram que el que usted llama "correcto". Tal vez le preocupa que los dígitos iniciales sean diferentes, pero esto no es realmente una medida de precisión allí.

Una nota final

A menos que lo esté haciendo para aprender cómo se comportan las funciones y cómo interactúa con él la precisión del punto flotante, no haga las cosas de esta manera . Incluso la propia documentación de Apfloat dice:

Este paquete está diseñado para una precisión extrema. El resultado puede tener unos pocos dígitos menos de lo que cabría esperar (unos 10) y los últimos dígitos (unos 10) en el resultado podrían ser inexactos. Si planea usar números con solo unos pocos cientos de dígitos, use un programa como PARI (es gratis y está disponible en ftp://megrez.math.u-bordeaux.fr ) o un programa comercial como Mathematica o Maple si es posible.

mpmath en python a esta lista como una alternativa gratuita ahora.


Para obtener una respuesta sobre el uso de aritmética de precisión arbitraria con el método integral descrito en el OP, consulte mi otra respuesta

Sin embargo , me intrigó esto y pensé que un método de suma de series debería ser más estable numéricamente. Encontré la representación de la serie Dirichlet en Wikipedia y la implementé (código completamente ejecutable a continuación).

Esto me dio una visión interesante. Si fijo la convergencia EPSILONde 1e-30recibo exactamente los mismos dígitos y exponente (es decir, 1e-70en la parte imaginaria) como Wolfram para zeta(100)y zeta(230+ 30i) y el algoritmo termina después de sólo 1 o 2 términos de añadir a la suma. Esto me sugiere dos cosas:

  1. Wolfram alpha utiliza este método de suma o algo similar para calcular los valores que devuelve.
  2. La condición "correcta" de estos valores es difícil de evaluar. Por ejemplo, zeta (100) tiene un valor exacto en términos de PI, por lo que puede ser juzgado. No sé si esta estimación de zeta(230+30i)es mejor o peor que la encontrada por el método integral
  3. Este método es realmente bastante lento para converger zeta(2+3i)y puede necesitar EPSILONser más bajo para ser utilizable.

También encontré un artículo académico que es un compendio de métodos numéricos para calcular zeta. ¡Esto me indica que el problema subyacente aquí es ciertamente "no trivial"!

De todos modos, dejo aquí la implementación de la suma de la serie como una alternativa para cualquier persona que pueda encontrarla en el futuro.

import java.io.PrintWriter; import org.apfloat.ApcomplexMath; import org.apfloat.Apcomplex; import org.apfloat.Apfloat; import org.apfloat.ApfloatMath; import org.apfloat.samples.Pi; public class ZetaSeries { //Number of sig figs accuracy. Note that infinite should be reserved private static long PRECISION = 100l; // Convergence criterion for integration static Apfloat EPSILON = new Apfloat("1e-30",PRECISION); static Apfloat one = new Apfloat("1",PRECISION); static Apfloat two = new Apfloat("2",PRECISION); static Apfloat minus_one = one.negate(); static Apfloat three = new Apfloat("3",PRECISION); private Apcomplex s = null; private Apcomplex s_plus_two = null; public ZetaSeries(Apcomplex s) { this.s = s; this.s_plus_two = two.add(s); } public static void main(String[] args) { Apfloat re = new Apfloat("230", PRECISION); Apfloat im = new Apfloat("30", PRECISION); Apcomplex s = new Apcomplex(re,im); ZetaSeries z = new ZetaSeries(s); System.out.println(z.findZeta()); } private Apcomplex findZeta() { Apcomplex series_sum = Apcomplex.ZERO; Apcomplex multiplier = (one.divide(this.s.add(minus_one))); int stop_condition = 1; long n = 1; while (stop_condition > 0) { Apcomplex term_to_add = sum_term(n); stop_condition = ApcomplexMath.abs(term_to_add).compareTo(EPSILON); series_sum = series_sum.add(term_to_add); //if(n%50 == 0) { System.out.println("At iteration " + n + " : " + multiplier.multiply(series_sum)); } n+=1; } return multiplier.multiply(series_sum); } private Apcomplex sum_term(long n_long) { Apfloat n = new Apfloat(n_long, PRECISION); Apfloat n_plus_one = n.add(one); Apfloat two_n = two.multiply(n); Apfloat t1 = (n.multiply(n_plus_one)).divide(two); Apcomplex t2 = (two_n.add(three).add(this.s)).divide(ApcomplexMath.pow(n_plus_one,s_plus_two)); Apcomplex t3 = (two_n.add(minus_one).add(this.s.negate())).divide(ApcomplexMath.pow(n,this.s_plus_two)); return t1.multiply(t2.add(t3.negate())); } }