Java - 将double转换为BigDecimal时出现奇怪的错误消息

时间:2015-08-08 22:12:10

标签: java double bigdecimal

在程序中,double被转换为BigDecimal。这会返回一条非常奇怪的错误消息。

public static double riemannFuncForm(double s) {
        double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*
            (Math.sin((Math.PI*s)/2))*gamma(1-s);

        if(s == 1.0 || (s <= -1 && s % 2 == 0) )
            return 0;
        else if (s >= 0 && s < 2)
            return getSimpsonSum(s);
        else if (s > -1 && s < 0)
            return term*getSimpsonSum(1-s);
        else 
            return term*standardZeta(1-s);
    }

BigDecimal val = BigDecimal.valueOf(riemannFuncForm(s));
System.out.println("Value for the Zeta Function = " 
                    + val.toEngineeringString());

返回

Exception in thread "main" java.lang.NumberFormatException

导致此错误消息的原因是什么? BigDecimal.valueOf(double)是否无法正常工作,因为这是通过另一种方法引用的?

完整计划

/**************************************************************************
**
**    Euler-Riemann Zeta Function           
**
**************************************************************************
**    XXXXXXXXXX
**    06/20/2015
**
**    This program computes the value for Zeta(s) using the standard form
**    of Zeta(s), the Riemann functional equation, and the Cauchy-Schlomilch
**    transformation. A recursive method named riemannFuncForm has been created
**    to handle computations of Zeta(s) for s < 2. Simpson's method is
**    used to approximate the definite integral calculated by the
**    Cauchy-Schlomilch transformation.
**************************************************************************/

import java.util.Scanner;
import java.math.*;

public class ZetaMain {

    // Main method
    public static void main(String[] args) {
        ZetaMain();       
    }

    // Asks the user to input a value for s.
    public static void ZetaMain() {
        double s = 0;
        double start, stop, totalTime;
        Scanner scan = new Scanner(System.in);
        System.out.print("Enter the value of s inside the Riemann Zeta " + 
                "Function: ");
        try {
                s = scan.nextDouble();
        }
        catch (Exception e) {
            System.out.println("You must enter a positive integer greater " + 
                    "than 1.");
        }
        start = System.currentTimeMillis();
        if (s == 1)
            System.out.println("The zeta function is undefined for Re(s) " +
                    "= 1.");
        else if (s < 2) {
            BigDecimal val = BigDecimal.valueOf(riemannFuncForm(s));
            System.out.println("Value for the Zeta Function = " 
                    + val.toEngineeringString());
        }
        else 
            System.out.println("Value for the Zeta Function = " 
                    + BigDecimal.valueOf(getStandardSum(s)).toString());
        stop = System.currentTimeMillis();
        totalTime = (double) (stop-start) / 1000.0;
        System.out.println("Total time taken is " + totalTime + " seconds.");

    }

    // Standard form of the Zeta function.
    public static double standardZeta(double s) {
        int n = 1;
        double currentSum = 0;
        double relativeError = 1;
        double error = 0.000001;
        double remainder;

        while (relativeError > error) {
            currentSum = Math.pow(n, -s) + currentSum;
            remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
            relativeError =  remainder / currentSum;
            n++;
        }
        System.out.println("The number of terms summed was " + n + ".");
        return currentSum;
    }

    // Returns the value calculated by the Standard form of the Zeta function.
    public static double getStandardSum(double s){
        return standardZeta(s);
    }

    // Approximation of the Gamma function through the Lanczos Approximation.
    public static double gamma(double s){
                    double[] p = {0.99999999999980993, 676.5203681218851, 
                        -1259.1392167224028, 771.32342877765313, 
                        -176.61502916214059, 12.507343278686905,
                        -0.13857109526572012, 9.9843695780195716e-6, 
                        1.5056327351493116e-7};

                    int g = 7;

                    // Implements Euler's Reflection Formula.
                    if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)
                            *gamma(1-s));

                    s -= 1;
                    double a = p[0];
                    double t = s + g + 0.5;
                    for(int i = 1; i < p.length; i++){
                            a += p[i] / (s+i);
                    }

                    return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)
                            *Math.exp(-t)*a;
            }

    /* Riemann's Functional Equation - Directly calculates the value of 
        Zeta(s) for s < 2.

        1. The first if statement handles the case when s < 0 and s is a 
            multiple of 2k. These are trivial zeroes where Zeta(s) is 0.

        2. The second if statement handles the values of 0 < s < 2. Simpson's 
           method is used to numerically compute an approximation of the 
           definite integral.

        3. The third if statement handles the values of -1 < s < 0. Recursion 
           is used alongside an approximation through Simpson's method.

        4. The last if statement handles the case for s <= -1 and is not a 
           trivial zero. Recursion is used directly against the standard form 
           of Zeta(s).
    */
    public static double riemannFuncForm(double s) {
        double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*
            (Math.sin((Math.PI*s)/2))*gamma(1-s);

        if(s == 1.0 || (s <= -1 && s % 2 == 0) )
            return 0;
        else if (s >= 0 && s < 2)
            return getSimpsonSum(s);
        else if (s > -1 && s < 0)
            return term*getSimpsonSum(1-s);
        else 
            return term*standardZeta(1-s);
    }

    // Returns the function referenced inside the right hand side of the 
    // Cauchy-Schlomilch transformation for Zeta(s).
    public static double function(double x, double s) {
        double sech = 1 / Math.cosh(x); // Hyperbolic cosecant
        double squared = Math.pow(sech, 2);
        return ((Math.pow(x, s)) * squared);
    }

 // Simpson's rule - Approximates the definite integral of f from a to b.
    public static double SimpsonsRule(double a, double b, double s, int n) {
        double simpson, dx, x, sum4x, sum2x;

        dx = (b-a) / n;
        sum4x = 0.0;
        sum2x = 0.0;

        // 4/3 terms
        for (int i = 1; i < n; i += 2) {
            x = a + i * dx;
            sum4x += function(x,s);
        }

        // 2/3 terms
        for (int i = 2; i < n-1; i += 2) {
            x = a + i * dx;
            sum2x += function(x,s);
        }

        // Compute the integral approximation.
        simpson = function(a,s) + function(a,b);
        simpson = (dx / 3)*(simpson + 4 * sum4x + 2 * sum2x);
        return simpson;
    }

    // Handles the error for for f(x) = t^s * sech(t)^2. The integration is
    // done from 0 to 100.
    // Stop Simspson's Method when the relative error is less than 1 * 10^-6
    public static double SimpsonError(double a, double b, double s, int n)
    {
        double futureVal;
        double absError = 1.0;
        double finalValueOfN;
        double numberOfIterations = 0.0;
        double currentVal = SimpsonsRule(a,b,s,n);

        while (absError / currentVal > 0.000001) {
            n = 2*n;
            futureVal = SimpsonsRule(a,b,s,n);
            absError = Math.abs(futureVal - currentVal) / 15;
            currentVal = futureVal;
        }

        // Find the number of iterations. N starts at 8 and doubles 
        // every iteration.
        finalValueOfN = n / 8;
        while (finalValueOfN % 2 == 0) {
            finalValueOfN = finalValueOfN / 2;
            numberOfIterations++;
        }
        System.out.println("The number of iterations is " 
                + numberOfIterations + ".");
        return currentVal;
    }


    // Returns an approximate sum of Zeta(s) through Simpson's rule.
    public static double getSimpsonSum(double s) {
        double constant = Math.pow(2, (2*s)-1) / (((Math.pow(2, s)) -2)*
                (gamma(1+s)));
        System.out.println("Did Simpson's Method.");
        return constant*SimpsonError(0, 100, s, 8);
    }
}

2 个答案:

答案 0 :(得分:2)

发生此错误,因为BigDecimal.valueOf(value)不接受“NaN”“Not a Number”作为参数,以下表达式将返回NaN

Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)

Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))将评估-0.0

并且此函数gamma(1-s)将评估“无限”

所以-0.0 *无穷大在java中等于NaN

请看这个知道什么时候Java可以产生NaN。

When can Java produce a NaN?

答案 1 :(得分:2)

  

为了解决这个问题,我是否必须将所有双重计算更改为BigDecimal计算?

不。您需要做的就是适当地捕获和处理NumberFormatException。或者,在尝试转换NaN之前测试Infdouble

在这种情况下,您只使用BigDecimal进行“工程”语法格式化。所以另一种选择是直接进行格式化。 (虽然我还没有找到一种简单的方法。)