Java 以双精度移动小数点

Java 以双精度移动小数点,java,double,decimal,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); double x=1234; 对于(int i=1;iNo-如果你想准确地存储十进制值,使用BigDecimaldouble不能准确地表示像0.1这样的数字,就像你可以用有限的十进制数字准确地写三分之一的值一样。这是由计算

所以我有一个等于1234的双精度集,我想把小数点移到12.34

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

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

对于(int i=1;iNo-如果你想准确地存储十进制值,使用
BigDecimal
double
不能准确地表示像0.1这样的数字,就像你可以用有限的十进制数字准确地写三分之一的值一样。

这是由计算机存储浮点数的方式造成的。它们不需要o完全正确。作为一名程序员,你应该通过阅读来熟悉处理浮点数的考验和磨难。

否,因为(实际上是所有浮点数类型)是大小和精度之间的折衷。虽然它们对许多任务非常有用,但如果需要任意精度,则应使用
BigDecimal
如果使用
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);
}

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

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

是的,有。每次双精度运算可能会失去精度,但每次运算的精度不同,可以通过选择正确的运算顺序来最小化。例如,当将一组数字相乘时,最好在相乘之前按指数对集合进行排序

任何一本关于数字运算的像样的书都描述了这一点。例如:

回答你的问题:

使用除法而不是乘法,这样可以得到正确的结果

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

对于(int i=1;i在金融软件中,用整数表示便士是很常见的。在学校,我们被教如何使用定点而不是浮点,但这通常是二的幂。用整数存储便士也可以称为“定点”

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

对于
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。他们有自己的格式LN(),带有便士代码。转换的原因是32位整数已经不够了。+/-20亿便士等于2000万美元,而这是为世界杯或奥运会而溢出的,我忘了


我发誓要保密。哦,好吧。在学术界,如果你出版是好事,在工业界,你要保密。

你可以尝试整数表示法

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

System.out.printf("%d.%02d",q, r);

有趣的是,很多帖子都提到要使用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构造函数特别提到使用字符串构造函数比使用数字构造函数更好。最终精度也受可选MathContext的影响


根据BigDecimal Javadoc可以创建一个完全等于0.1的BigDecimal,只要你使用字符串构造函数。

Argh,我刚刚写了一个解释,链接到完全相同的位置。+1。@Lord Haha,对不起。我不管怎样都被困了。:-)我想这就是为什么,但我想知道是否有一些创造性的方法来移动小数点?因为可以将12.34干净地存储在一个双精度中,它只是不喜欢乘以。1如果可以将12.34干净地存储在一个双精度中,你不认为Java会这样做吗?不是。你必须使用其他数据类型(如BigDecimal)还有,你为什么不直接除以100,而不是在一个循环中进行呢?是的,除以100会得到一个干净的12.34…谢谢:-PI真不敢相信我一开始就没想到这么做!谢谢:-虽然100可以用二进制格式精确表示,但除以100不能精确表示。因此,编写
1234/100
,正如你所做的那样,对根本问题没有任何作用——它应该完全等同于写
1234*0.01
@Peter Lawrey:你能解释一下为什么这个数字是奇数还是偶数会影响舍入吗?我认为/=100和*=0.01是一样的,因为即使100是整数,它也会是整数无论如何,由于类型强制,转换为100.0。
/100
*0.01
彼此等效,但与OP的
*0.1*0.1
不同。我想说的是,平均来说,乘以0.1两次会比乘以0.01一次引入更大的错误;但我很乐意承认@JasperBekkers的观点是100Dan:为什么?这是金融应用程序(或任何其他应用程序,即使是很小的舍入误差都是不可接受的)的正确方法,同时仍然保持硬件级别的速度。(当然,它将被包装在一个类中,通常情况下,不是每次都写出来)有一个小问题
int i =1234;
int q = i /100;
int r = i % 100;

System.out.printf("%d.%02d",q, r);
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