Java DecimalFormat 舍入问题(一致性问题)
Java DecimalFormat rounding issue ( consistency problem)
我在尝试将双精度四舍五入到小数点后 2 位时看到一些奇怪的行为
下面是代码
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_EVEN);
double f1 = 100.845;
double f2 = 1440.845;
System.out.println( df.format(f1));
System.out.println( df.format(f2));
这输出
100.84
1,440.85
我原以为第一个值是 100.85。
当我进一步调查时,我发现了以下内容
101.845 --> 100.84
102.845 --> 102.84
103.845 --> 103.84
.
.
255.845 --> 255.84
**256.845 --> 256.85**
257.845 --> 256.85
.
.
我认为它一定与精度有关,因为从 .84 到 .85 的转换发生在 255( 2^8 -1) 左右。但是,我没有计算这个值(至少在这个示例代码中没有)。
谁能解释一下为什么会这样?
谢谢
当使用 HALF_EVEN
时,它向“最近的邻居”舍入,除非两个邻居是等距的。如果它们是等距的,它向左边的偶数邻居四舍五入...
在你的例子中,100.845
最后一个数字 5
是等距的,所以它四舍五入到左边最近的偶数邻居 4
。
在这里,您使用的是 double
,在内存中,它可以与该值略有不同。为确保您要发送的数字不是等距的,请为您的 double
添加精度误差 + 1e-6
。
这里的问题是因为这两个双精度值都不完全等于 Java 代码中使用的十进制表示;它们是一个接近的浮点值。
以下是打印其精确值的一种方法:
System.out.println(new BigDecimal(100.845));
System.out.println(new BigDecimal(1440.845));
这输出:
100.844999999999998863131622783839702606201171875
1440.845000000000027284841053187847137451171875
100.8449...
向下舍入为 100.84
,因为它最接近 100.84
。
1440.8450...
四舍五入到 100.85
,因为它最接近 100.85
。
在这两种情况下,半偶数逻辑都不适用,因为这两个数字都不是两个潜在舍入目标的中间值。
相比之下,如果您使用 可以 准确表示这些值的数字格式(例如 BigDecimal
),您将看到预期的舍入:
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_EVEN);
BigDecimal d1 = new BigDecimal("100.845");
BigDecimal d2 = new BigDecimal("1440.845");
System.out.println( df.format(d1));
System.out.println( df.format(d2));
输出:
100.84
1,440.84
我在尝试将双精度四舍五入到小数点后 2 位时看到一些奇怪的行为
下面是代码
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_EVEN);
double f1 = 100.845;
double f2 = 1440.845;
System.out.println( df.format(f1));
System.out.println( df.format(f2));
这输出
100.84
1,440.85
我原以为第一个值是 100.85。
当我进一步调查时,我发现了以下内容
101.845 --> 100.84
102.845 --> 102.84
103.845 --> 103.84
.
.
255.845 --> 255.84
**256.845 --> 256.85**
257.845 --> 256.85
.
.
我认为它一定与精度有关,因为从 .84 到 .85 的转换发生在 255( 2^8 -1) 左右。但是,我没有计算这个值(至少在这个示例代码中没有)。
谁能解释一下为什么会这样?
谢谢
当使用 HALF_EVEN
时,它向“最近的邻居”舍入,除非两个邻居是等距的。如果它们是等距的,它向左边的偶数邻居四舍五入...
在你的例子中,100.845
最后一个数字 5
是等距的,所以它四舍五入到左边最近的偶数邻居 4
。
在这里,您使用的是 double
,在内存中,它可以与该值略有不同。为确保您要发送的数字不是等距的,请为您的 double
添加精度误差 + 1e-6
。
这里的问题是因为这两个双精度值都不完全等于 Java 代码中使用的十进制表示;它们是一个接近的浮点值。
以下是打印其精确值的一种方法:
System.out.println(new BigDecimal(100.845));
System.out.println(new BigDecimal(1440.845));
这输出:
100.844999999999998863131622783839702606201171875
1440.845000000000027284841053187847137451171875
100.8449...
向下舍入为 100.84
,因为它最接近 100.84
。
1440.8450...
四舍五入到 100.85
,因为它最接近 100.85
。
在这两种情况下,半偶数逻辑都不适用,因为这两个数字都不是两个潜在舍入目标的中间值。
相比之下,如果您使用 可以 准确表示这些值的数字格式(例如 BigDecimal
),您将看到预期的舍入:
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_EVEN);
BigDecimal d1 = new BigDecimal("100.845");
BigDecimal d2 = new BigDecimal("1440.845");
System.out.println( df.format(d1));
System.out.println( df.format(d2));
输出:
100.84
1,440.84