十进制算术表达式的意外结果

时间:2012-11-15 14:07:59

标签: java

我有一些带有算术表达式的业务逻辑,其结果如下

(10.0 * 20.58)/1.0=205.7999..98
(6.0 * 37.9)/1.0=227.3999..98
(5.0 * 50.0)/1.0=250.0
(10.0 * 37.9)/1.0=379.0

但预期结果

(10.0 * 20.58)/1.0=205.8
(6.0 * 37.9)/1.0=227.4
(5.0 * 50.0)/1.0=250.0
(10.0 * 37.9)/1.0=379.0

我不清楚为什么我们得到.999..98分数部分?由于我的等于比较失败和业务逻辑。我们使用

的情况很少
amt = (double)Math.round(orderAmt*100000)/100000;

但是,在我们有双重算术表达的每个地方都不可能这样做。

我想知道为什么我们会随机获得这样的结果,是否有可能将结果舍入到5位小数而不是每次舍入?

5 个答案:

答案 0 :(得分:1)

您可以使用BigDecimal进行舍入

BigDecimal bd = new BigDecimal((10.0 * 20.58)/1.0) ;
bd = bd.setScale(4, RoundingMode.UP);

使用静态方法

public static double round(double value, int digits) {
    BigDecimal bd = new BigDecimal(value);
    return bd.setScale(digits, RoundingMode.UP).doubleValue();
}

RoundingMode有:

RoundingMode.UP;
RoundingMode.DOWN;
RoundingMode.HALF_DOWN;
RoundingMode.HALF_EVEN;

答案 1 :(得分:1)

基本问题是

System.out.println(10.0 * 20.58);

打印

205.79999999999998
由于20.58

中的表示错误,

有一个小的舍入误差

您需要

  • 在比较前对结果进行四舍五入。
  • 使用允许出现错误的比较
  • 使用BigDecimal(在大多数情况下过度杀戮)
  • 使用美分而不是美元,即以固定精度使用intlong

在最后一种情况下,相同的操作将会读取

System.out.println(10 * 2058);

打印

20580

这是你需要的值的100倍作为其固定精度,例如美分而非美元。

答案 2 :(得分:1)

对于基数10,有些分数无法用有限的位数精确表达,例如1/3 = 0.33333333 ....

与基数2相同,除了产生这种结果的分频器不是我们习惯的分频器,例如,对于20.58,即2058/100,情况就是如此。

在内部,双精度数和浮点数用位(非数字)存储,因此double或float的确切值不能存储在计算机的内存中。每次使用此值执行操作时,由于近似值,您会得到一个小的移位,当转换回十进制格式进行打印时,该移动变得可见。

在进行精度很重要的计算时,你必须注意这一点。

所以你有两个解决方案:

  • 以十进制类型存储您的所有数字,并使用它执行所有计算。这将达到准确性但性价比。
  • 您还可以使用double或float保留所有计算,并使用固定的位数格式仅用于打印结果。

答案 3 :(得分:0)

使用float代替double

http://ideone.com/L9vwR8

System.out.println((float)((10.0f * 20.58f)/1.0f));

输出

  

205.8

答案 4 :(得分:0)

您可能希望使用double进行舍入,如下所示:

    double roundingPlaces = 10.0;//use 10.0 for single decimal digit rounding
    double a1 = 10.0;
    double b1 = 20.58;
    double c1 = 1.0;
    System.out.println(Math.round((a1*b1*roundingPlaces)/c1)/roundingPlaces);

这打印205.8。

    float fa1 = (float) 10.0;
    float fb1 = (float)20.58;
    float fc1 = (float)1.0;
    System.out.println(fa1*fb1/fc1);    

这也打印205.8