将小数位移到一个double中

Bla*_*Cow 96 java double decimal

所以我有一个等于1234的双重设置,我想将小数位移到12.34

所以要做到这一点,我将.1乘以1234两次,有点像这样

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

这将打印结果"12.340000000000002"

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

Pet*_*rey 186

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

您遇到的问题是0.1不是精确表示,并且通过执行两次计算,您将复合该错误.

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

double x = 1234;
x /= 100;
System.out.println(x);
Run Code Online (Sandbox Code Playgroud)

打印:

12.34
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为Double.toString(d)代表您执行少量舍入,但它并不多.如果你想知道它没有四舍五入的样子:

System.out.println(new BigDecimal(0.1));
System.out.println(new BigDecimal(x));
Run Code Online (Sandbox Code Playgroud)

打印:

0.100000000000000005551115123125782702118158340454101562
12.339999999999999857891452847979962825775146484375
Run Code Online (Sandbox Code Playgroud)

简而言之,无论您是否明确地执行此操作,舍入对于浮点的合理答案都是不可避免的.


注意:x / 100并且x * 0.01在舍入错误时并不完全相同.这是因为第一个表达式的舍入误差取决于x的值,而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);
}
Run Code Online (Sandbox Code Playgroud)

版画

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
Run Code Online (Sandbox Code Playgroud)

  • 我简直不敢相信我没想到这样做!谢谢:-P (25认同)
  • 虽然100可以用二进制格式精确表示,但除以100不能完全表示.因此,正如你所做的那样写"1234/100"并没有真正对基本问题做任何事情 - 它应该完全等于编写``1234*0.01``. (6认同)

Jon*_*eet 52

否 - 如果要准确存储小数值,请使用BigDecimal.double根本不能准确地表示像0.1这样的数字,只要你能用有限的十进制数字写出三分之一的值.


Aug*_*sto 46

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

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

产量

12.34
Run Code Online (Sandbox Code Playgroud)

  • 评分较高的答案在技术上更具洞察力,但这是OP问题的正确答案.我们通常不关心double的*轻微*不准确,所以BigDecimal是矫枉过正,但是在显示时我们经常想确保输出符合我们的直觉,所以`System.out.printf()`是正确的方法. (8认同)

Ter*_*vis 27

在财务软件中,通常使用整数来获得便士.在学校,我们被教导如何使用定点而不是漂浮,但这通常是2的幂.以整数存储便士也可称为"固定点".

int i=1234;
printf("%d.%02d\r\n",i/100,i%100);
Run Code Online (Sandbox Code Playgroud)

在课堂上,我们一般被问到什么数字可以在基数中准确表示.

对于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亿便士是2千万美元,而世界杯或奥运会也是如此.

我发誓保密.那好吧.在学术界,如果你发表的话很好; 在工业中,你保守秘密.


Ang*_*Koh 12

你可以尝试整数表示

int i =1234;
int q = i /100;
int r = i % 100;

System.out.printf("%d.%02d",q, r);
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案有一个小问题 - 如果剩余的`r`小于10,则不会发生0填充,1204会产生12.4的结果.正确的格式字符串更类似于"%d.%02d" (7认同)
  • @Dan:为什么?对于金融应用程序(或任何其他即使很小的舍入错误也是不可接受的应用程序),这是正确的方法,同时仍然保持硬件级别的速度.(当然,它会被包装在一个类中,通常,每次都不会写出来) (5认同)

Can*_*ice 10

这是由计算机存储浮点数的方式引起的.他们并没有这么做.作为程序员,您应该阅读此浮点指南,以熟悉处理浮点数的试验和磨难.


Jus*_*owe 9

有趣的是,很多帖子提到使用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")));
Run Code Online (Sandbox Code Playgroud)

给出这个输出

12.34
12.34000000000000025687785232264559454051777720451354980468750
12.34
Run Code Online (Sandbox Code Playgroud)

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

根据BigDecimal Javadoc ,如果使用String构造函数,可以创建一个完全等于0.1 的BigDecimal .


小智 5

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

关于数字运算的任何体面的书都描述了这一点.例如: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);
Run Code Online (Sandbox Code Playgroud)