我正在制作一个Java程序来计算Simpson的积分规则。这是我的代码。注意count == 4,9,10,11的输出值中的第二列数字。它们不是我需要的数字,它们不遵循这种模式。我需要这些数字是准确的。发生了什么,我该如何解决?
public static void main(String[] args)
{
double totalS = 0.0;
int count = 0;
for(double i=0; i< 4; i += 0.4 )
{
count++;
totalS += Sfunction(i, count);
System.out.println(count + " " + i + " " + totalS);
}
}
public static double Sfunction(double f1, int count)
{
double value;
if (f1 == 0.0 || f1 == 4.0)
value = Math.cos(Math.sqrt(f1));
else if ((count % 2) == 1)
value = 2 * Math.cos(Math.sqrt(f1));
else
value = 4 * Math.cos(Math.sqrt(f1));
return value;
}
我得到了输出:
1 0.0 1.0
2 0.4 4.226313639540303
3 0.8 5.478244888601832
4 1.2000000000000002 7.30884788480188
5 1.6 7.911122809972827
6 2.0 8.534897589034324
7 2.4 8.578100205110182
8 2.8 8.168723348285942
9 3.1999999999999997 7.736055200662704
10 3.5999999999999996 6.452869366954546
11 3.9999999999999996 5.620575693860261
答案 0 :(得分:7)
每次绕过你的循环,你都会在0.4到i的不精确加法中复杂化错误。
相反,使用循环计数器的整数值,并对其进行缩放以更好地逼近值:
for ( int count = 0; count < 10; ++count ) {
final double i = 0.4 * count;
System.out.println ( ( count + 1 ) + " " + i );
}
这不会消除浮点错误,但这意味着它不会在每次迭代时增加。要从输出中删除错误,请将输出格式化为合理的小数位数:
for ( int count = 0; count < 10; ++count ) {
final double i = 0.4 * count;
System.out.printf ( "%2d %.1f\n", ( count + 1 ), i );
}
答案 1 :(得分:6)
这是一个经典的浮点问题。如果您需要小数精度,则应使用BigDecimal
答案 2 :(得分:4)
这是how floating point numbers work in computers。
您可以围绕显示,但下面的表示不会更改。使用java.text.DecimalNumberFormat舍入到两位小数。
答案 3 :(得分:1)
你所看到的是floating point precision error的结果,这些数字并没有像你想象的那样存储。您可以将答案舍入到小数点后1位以消除错误......但这只是在java中存储双精度的结果。
答案 4 :(得分:1)
这里有关于这个主题的一些好的阅读:Why do simple math operations on floating point return unexpected (inaccurate) results in VB.Net and Python?
答案 5 :(得分:1)
您的问题是您使用的浮点运算只能近似值,但假设您具有无限精度。你不应该用浮点数做这样的等式测试:
if (f1 == 0.0 || f1 == 4.0)
任何具有浮点数的相等测试都是代码气味。使用浮点数时,您应始终检查它是否在某个范围内,例如在3.9999到4.0001范围内。
在这个具体的例子中,您还可以轻松地使用另一个名为count
的参数,它是一个int。你可以做那个相等的测试。也许你可以测试一下。
答案 6 :(得分:1)
尝试只用一个十进制数字打印它们:
System.out.printf("%.1f", Math.E); // prints 2.7
System.out.printf("%.2f", Math.E); // prints 2.72
System.out.printf("%.3f", Math.E); // prints 2.718
甚至尝试为您的数字运算方法指定关键字 strictfp
答案 7 :(得分:1)
从您的循环条件来看,您似乎根本不需要处理第11行。我建议您使用整数循环索引并使用它来计算传递给Sfunction
的值。以下内容应该与您现在拥有的内容相同(除了它排除了第11行)。
double totalS = 0.0;
for( int i = 1; i <= 10; i++ )
{
double f1 = 0.4 * (i - 1);
totalS += Sfunction(f1, i);
System.out.println(i + " " + f1 + " " + totalS);
}
您可以使用DecimalFormat解决打印精度问题,如其他答案所示。