在程序中,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);
}
}
答案 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。
答案 1 :(得分:2)
为了解决这个问题,我是否必须将所有双重计算更改为BigDecimal计算?
不。您需要做的就是适当地捕获和处理NumberFormatException。或者,在尝试转换NaN
之前测试Inf
和double
。
在这种情况下,您只使用BigDecimal
进行“工程”语法格式化。所以另一种选择是直接进行格式化。 (虽然我还没有找到一种简单的方法。)