Answers:
如果使用double
或float
,则应使用舍入或期望看到一些舍入错误。如果您无法执行此操作,请使用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 / 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);
}
版画
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
1234/100
正如您所做的那样,写作实际上并没有对根本的问题做任何事情,它应该与写作完全相同1234 * 0.01
。
/100
并且*0.01
彼此相等,但不等同于OP *0.1*0.1
。
如果只是格式化,请尝试使用printf
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.printf("%.2f",x);
输出
12.34
System.out.printf()
正确的方法是。
在财务软件中,通常使用整数作为便士。在学校里,我们被教导如何使用定点数而不是浮点数,但这通常是二的幂。以整数存储便士也可以称为“固定点”。
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亿便士等于2,000万美元,我忘了世界杯或奥运会的溢价。
我发誓要保密。那好吧。在学术界,如果好的话,你可以发表;在行业中,您要保密。
您可以尝试整数表示
int i =1234;
int q = i /100;
int r = i % 100;
System.out.printf("%d.%02d",q, r);
r
小于10,则不会出现0填充,并且1204的结果为12.4。正确的格式字符串更类似于“%d。%02d”
这是由计算机存储浮点数的方式引起的。他们没有完全做到这一点。作为程序员,您应该阅读此浮点指南,以熟悉处理浮点数的试验和麻烦。
有趣的是,很多帖子都提到要使用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 ,如果您使用String构造函数,则可以创建一个完全等于0.1 的BigDecimal 。
就在这里。每次执行两次操作都可能会丢失精度,但是每种操作的精度会有所不同,可以通过选择正确的操作顺序来最大程度地降低精度。例如,将一组数字相乘时,最好在相乘之前按指数对组进行排序。
任何有关数字处理的不错的书都对此进行了描述。例如: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);