在双精度上移动小数点以上

所以我有一个双重设置等于1234,我想移动一个小数点,使其12.34

所以要做到这一点,我把两倍乘以1到1234,就像这样

double x = 1234; for(int i=1;i<=2;i++) { x = x*.1; } System.out.println(x); 

这将打印结果“12.340000000000002”

有没有一种方法,而不是简单地格式化到两位小数,有正确的双存储12.34?

如果使用doublefloat ,则应使用舍入或期望看到一些舍入错误。 如果你不能这样做,使用BigDecimal

您遇到的问题是0.1不是一个确切的表示,并且通过执行两次计算,您正在复合该错误。

但是,100可以准确表示,所以请尝试:

 double x = 1234; x /= 100; System.out.println(x); 

打印:

 12.34 

这是有效的,因为Double.toString(d)代表你进行了一些四舍五入的处理,但是并不多。 如果你想知道没有四舍五入的样子,

 System.out.println(new BigDecimal(0.1)); System.out.println(new BigDecimal(x)); 

打印:

 0.100000000000000005551115123125782702118158340454101562 12.339999999999999857891452847979962825775146484375 

简而言之,四舍五入是不可避免的,无论您是否明确地这样做了明智的答案。


注意:对于舍入误差, x / 100x * 0.01不完全相同。 这是因为第一个expression式的舍入误差取决于x的值,而第二个expression式的0.01有固定的舍入误差。

 for(int i=0;i<200;i++) { double d1 = (double) i / 100; double d2 = i * 0.01; if (d1 != d2) System.out.println(d1 + " != "+d2); } 

版画

 0.35 != 0.35000000000000003 0.41 != 0.41000000000000003 0.47 != 0.47000000000000003 0.57 != 0.5700000000000001 0.69 != 0.6900000000000001 0.7 != 0.7000000000000001 0.82 != 0.8200000000000001 0.83 != 0.8300000000000001 0.94 != 0.9400000000000001 0.95 != 0.9500000000000001 1.13 != 1.1300000000000001 1.14 != 1.1400000000000001 1.15 != 1.1500000000000001 1.38 != 1.3800000000000001 1.39 != 1.3900000000000001 1.4 != 1.4000000000000001 1.63 != 1.6300000000000001 1.64 != 1.6400000000000001 1.65 != 1.6500000000000001 1.66 != 1.6600000000000001 1.88 != 1.8800000000000001 1.89 != 1.8900000000000001 1.9 != 1.9000000000000001 1.91 != 1.9100000000000001 

否 – 如果要准确存储小数值,请使用BigDecimaldouble简直不能像0.1 那样表示一个数字,也不能完全用有限的十进制数字来表示第三个数值。

如果只是格式化,请尝试printf

  double x = 1234; for(int i=1;i<=2;i++) { x = x*.1; } System.out.printf("%.2f",x); 

产量

 12.34 

在金融软件中,通常使用整数作为便士。 在学校,我们被教导如何使用定点而不是浮动,但通常是两个权力。 以整数存储便士可能被称为“定点”。

 int i=1234; printf("%d.%02d\r\n",i/100,i%100); 

在课堂上,我们总体上被问到什么样的数字可以在一个基数中被精确地表示。

对于base=p1^n1*p2^n2 …可以表示任意N,其中N = n * p1 ^ m1 * p2 ^ m2。

base=14=2^1*7^1 …你可以表示1/7 1/14 1/28 1/49但不是1/3

我知道财务软件 – 我把Ticketmaster的财务报告从VAX asm转换成PASCAL。 他们有自己的formatln()代码便士。 转换的原因是32位整数已经不够了。 +/- 20亿便士是2000万美元,而这个世界杯或奥运会溢出了,我忘记了。

我发誓要保密。 好吧。 在学术界,如果你发表, 在行业中,你保守秘密。

你可以尝试整数的表示forms

 int i =1234; int q = i /100; int r = i % 100; System.out.printf("%d.%02d",q, r); 

这是由计算机存储浮点数的方式造成的。 他们没有这么做。 作为程序员,您应该阅读本浮点指南以熟悉处理浮点数的尝试和磨难。

有趣的是,无数post提到使用BigDecimal,但没有人会根据BigDecimal给出正确的答案? 因为即使使用BigDecimal,您仍然可能会出错,如代码所示

 String numstr = "1234"; System.out.println(new BigDecimal(numstr).movePointLeft(2)); System.out.println(new BigDecimal(numstr).multiply(new BigDecimal(0.01))); System.out.println(new BigDecimal(numstr).multiply(new BigDecimal("0.01"))); 

给出这个输出

 12.34 12.34000000000000025687785232264559454051777720451354980468750 12.34 

BigDecimal构造函数特别提到使用String构造函数比数字构造函数更好。 终极精度也受可选的MathContext的影响。

根据BigDecimal Javadoc ,可以创build一个完全等于0.1的BigDecimal,只要使用String构造函数即可。

就在这里。 对于每次双重操作,您可能会失去准确性,但每次操作的准确性会有所不同,并且可以通过select正确的操作顺序将其最小化。 例如,当乘以一组数字时,最好在乘法之前按指数sorting。

任何有关数字计算的正派书籍都描述了这一点。 例如: http : //docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

并回答你的问题:

用分而不乘,这样你就得到了正确的结果。

  double x = 1234; for(int i=1;i<=2;i++) { x = x / 10.0; } System.out.println(x); 

不,因为Java浮点types (实际上是所有浮点types)在大小和精度之间进行权衡。 虽然它们对于很多任务非常有用,但如果您需要任意精度,则应该使用BigDecimal