【问题标题】:Java DecimalFormat HALF_UP rounding errorJava DecimalFormat HALF_UP 舍入错误
【发布时间】:2017-07-14 16:51:23
【问题描述】:

我正在使用带有 HALF_UP 舍入模式的 DecimalFormat,我有一个无法正常工作的 escenery,我不知道为什么。

DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.HALF_UP);
float tmp = (float) (0.5 * 1.05);
df.format(tmp);
float mul = Float.parseFloat(df.format(tmp));

mul 变量值我希望有 0.53 值,我收到了 0.52 值。

我使用的是 Java 1.8.0_131。

已解决的最终代码

BigDecimal mul = new BigDecimal(0.5).multiply(new igDecimal(1.05));
mul = mul.setScale(2, RoundingMode.HALF_UP);
System.out.println(mul);

【问题讨论】:

  • 感谢您的评论,但我需要舍入,因为 HALF_UP 必须工作“舍入模式以向“最近的邻居”舍入,除非两个邻居是等距的,在这种情况下舍入。” Oracle Documentation
  • floatdouble 无法精确存储值...参见:stackoverflow.com/q/3413448/4899193
  • 这工作System.out.println(df.format(0.5 * 1.05)); - 当然是双打
  • 我不认为....尝试打印出tmp,例如System.out.println(""+tmp);
  • 根据下面的答案,double 就足够了,而float 则不然。而tmp 被声明为float....

标签: java rounding bigdecimal


【解决方案1】:

您使用的是float 数据类型。

此数据类型无法精确保存值0.525。请参阅此代码以使其清楚:

float value = (float) (0.5 * 1.05);
DecimalFormat df = new DecimalFormat("#.########################");
System.out.println(df.format(value));

打印出来:

0.5249999761581421

使用模式RoundingMode.HALF_UP 舍入这样的值将正确产生0.52

double似乎能够精确存储值0.525

double value = 0.5 * 1.05;
DecimalFormat df = new DecimalFormat("#.########################");
System.out.println(df.format(value));

这将打印预期值:

0.525

使用模式 RoundingMode.HALF_UP 舍入该值现在将产生 0.53

注意:即使是double 数据类型也不能精确地存储值!

看看@MarkDickinson 的评论。存储的值是0.52500000000000002220446049250313080847263336181640625,它恰好大于0.525,并且只是偶然四舍五入到预期值。

那该怎么办?

数据类型floatdouble 是基于二进制的,而我们人类在处理数字时倾向于认为基于十进制。阅读文章"What Every Computer Scientist Should Know About Floating-Point Arithmetic" 了解更多信息。

解决方案是使用基于十进制的数据类型,存在于BigDecimal

【讨论】:

  • 这个答案具有误导性; double 无法准确地存储值 0.525:它存储 0.52500000000000002220446049250313080847263336181640625。因为该值恰好高于0.525,所以向上舍入。尝试使用0.7 * 1.05,您会看到它向下取整而不是向上取整。如果 OP 关心 decimal 中途情况的正确舍入,他们需要使用基于小数的数字类型。
  • 感谢您的快速回答,但我的四舍五入继续出现问题:double tmp = 0.5 * 1.05; DecimalFormat df = new DecimalFormat("#.##"); df.setRoundingMode(RoundingMode.HALF_UP); System.out.println(df.format(tmp)); Thats 返回 1.52
  • @MarkDickinson 感谢您的发现。我不知何故错过了它。改变了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
相关资源
最近更新 更多