繁体   English   中英

java for-loop问题

[英]java for-loop problem

我正在制作一个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.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 );
    }

这是一个经典的浮点问题。 如果您需要小数精度,则应使用BigDecimal

这是浮点数在计算机中的工作方式

您可以围绕显示,但下面的表示不会更改。 使用java.text.DecimalNumberFormat舍入到两个小数位。

您所看到的是浮点精度错误的结果,数字不会像您可能想到的那样存储。 您可以将答案舍入到小数点后1位以消除错误...但这只是在java中存储双打的结果。

您的问题是您使用的浮点运算只能近似值,但假设您具有无限精度。 你不应该用浮点数做这样的等式测试:

 if (f1 == 0.0 || f1 == 4.0)

任何具有浮点数的相等测试都是代码气味。 使用浮点数时,应始终检查它是否在某个范围内,例如在3.9999到4.0001范围内。

在这个具体的例子中,您还可以轻松地使用另一个名为count参数,它是一个int。 可以用它进行相等的测试。 也许你可以测试一下。

尝试只用一个十进制数字打印它们:

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

从您的循环条件看,您似乎根本不需要处理第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解决打印精度问题,如其他答案所示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM