Java中的Math.pow给出了意想不到的小数精度

时间:2012-05-18 19:37:43

标签: java python clojure

请有人帮助我使用java浮动。我观察到与java有些不一致 例如

Math.pow(10.0,-2)==0.01
Math.pow(10.0,-3)=0.0010 (instead of 0.001)
Math.pow(10.0,-4)=1.0 E-4
printf("%g",Math.pow(10,-4)) =0.000100000 

而使用Python:

10**-1=0.1
10**-2=0.01
10**-3=0.001

使用Clojure 1.4

(Math/pow 10 -2) = 0.01
(Math/pow 10 -3) = 0.001

我的问题是,与Python相比,如何在Java中获得类似的结果 换句话说,如何在没有任何尾随零的情况下获得精确结果。为什么添加这些尾随零,是否有任何方法可以抑制它们。

2 个答案:

答案 0 :(得分:5)

很容易解释尾随零的来源。

对于%g,这很简单:%g默认情况下始终显示6位有效数字,因此您会看到

1.00000
0.100000
0.0100000
0.00100000
0.000100000
1.00000e-5
1.00000e-6
...

您可以通过将精度设置为1个有效数字来摆脱它们,但您可能不希望这样,因为例如,它也会围绕2.5到3。

执行println会直接显示Double.toString()定义的结果(double)的表示形式:

  

结果是一个字符串,表示参数的符号和大小(绝对值)。 [...]幅度 m

[...]

  

如果 m 大于或等于10 -3 但小于10 7 ,那么它表示为整数部分 m ,十进制形式,没有前导零,后跟'。' ('\ u002E'),后跟一个或多个十进制数字,表示 m 的小数部分。

[...]

  

如果 m 小于10 -3 或大于或等于10 7 ,则表示为所谓的“计算机化的科学记数法。“设 n 是唯一的整数,使得10 n m &lt; 10 名词 1 ;然后让 a 成为 m 和10 n 的数学精确商,这样1≤ a < / em>&lt; 10.然后将幅度表示为 a 的整数部分,作为单个十进制数字,后跟“。”。 ('\ u002E'),后跟代表 a 的小数部分的十进制数字,后跟字母'E'('\ u0045'),后跟 n的表示作为十进制整数,由方法Integer.toString(int)生成。

[...]

  

m a 的小数部分必须打印多少位数?必须至少有一个数字来表示小数部分,并且除此之外必须有多个,但只需要多少个,更多的数字来唯一地区分参数值和double类型的相邻值。

因此你看到了

1.0
0.01
0.0010
1.0E-4
9.999999999999999E-6
1.0E-6
...

那么如何摆脱尾随的零呢?

一种方法是使用BigDecimal,其stripTrailingZeros()方法。 但你必须小心使用它:

System.out.println(BigDecimal.TEN.pow( -4 ,MathContext.DECIMAL64).stripTrailingZeros());

将打印预期的

0.0001

System.out.println(new BigDecimal(Math.pow(10,-4)).stripTrailingZeros());

将打印

0.000100000000000000004792173602385929598312941379845142364501953125

因为恰好是最接近10 -4 double的确切值。

如果您不想在BigDecimal中完成所有数学计算,那么您可以使用%g获得舍入结果的字符串表示(这使您有机会控制精度),从中创建一个BigDecimal,并打印结果:

System.out.println(new BigDecimal( String.format("%g", Math.pow(10,-4) ) ).stripTrailingZeros());

答案 1 :(得分:0)

如果您的问题只是显示,可以使用DecimalFormat和'#'http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html