Java双到长转换错误之谜
谁能给我解释一下吗Java双到长转换错误之谜,java,Java,谁能给我解释一下吗 public static void main(String[] args) { long a = 0; long b = 0; Random r = ThreadLocalRandom.current(); for (int i = 0; i < 1000; i++) { double d = r.nextDouble()*(r.nextBoolean() ? 1.0 : -1.0); a
public static void main(String[] args) {
long a = 0;
long b = 0;
Random r = ThreadLocalRandom.current();
for (int i = 0; i < 1000; i++) {
double d = r.nextDouble()*(r.nextBoolean() ? 1.0 : -1.0);
a += d*100;
b += (long)(100*d);
//System.out.println(a + " " + b + " " + d);
}
System.out.println(a);
System.out.println(b);
}
publicstaticvoidmain(字符串[]args){
长a=0;
长b=0;
Random r=ThreadLocalRandom.current();
对于(int i=0;i<1000;i++){
双d=r.nextDouble()*(r.nextBoolean()?1.0:-1.0);
a+=d*100;
b+=(长)(100*d);
//系统输出打印项次(a+“”+b+“”+d);
}
系统输出打印项次(a);
系统输出打印ln(b);
}
为什么是a!=b在这个循环的末尾。这是矩阵中的小故障吗?如果我去掉“d”的随机符号,那么a==b。为什么?根据+=
的规定如下:
形式为E1 op=E2的复合赋值表达式等价于E1=(T)((E1)op(E2)),其中T是E1的类型,但E1仅计算一次
这意味着你的两个陈述
a += d*100;
b += (long)(100*d);
基本相当于
a = (long) (a + d*100);
b = (long) (b + (long)(100*d));
在a
的情况下,加法介于long
值和double
值之间,因此整个计算将在double
域中完成
在b
的情况下,加法的两部分都是long
值,因此计算将使用long
数学
由于
long
和double
具有不同的值范围,因此结果可能会有所不同。这里发生的是四舍五入
您的作业:
a += d*100
b += (long)(100*d);
将按以下方式执行:
a = (long)(a + d * 100);
b = b + (long)(100 * d);
在一个循环之后,当a和b为正而d为负时,a和b可能不同,反之亦然。将d*100添加到a时,您正在添加精确值(例如-1.1),而对于b,它将首先四舍五入到-1。
让我们举个例子。在循环开始时,我们将获得以下值:
a = b = 1024
d = -0.178
单次运行的最终结果将是:
a = (long)(1024-17.8) = (long)(1006.2) = 1006
b = 1024-(long)17.8 = 1024-17 = 1007
这对我来说仍然没有意义。如果我们对不同的原语超出值范围,这是有意义的。但如果我们启动a&b=231和d=-0.2779593247777002,那么a=>203和b=>204显然没有超出范围。但它给了我另一个想法,它可能是一个舍入误差?不认为舍入错误会导致这种现象……考虑<代码>(long)(1 +(-0.1))< /> > vs>代码> 1L+((long)-0.1)< /代码>,这似乎是一个“舍入问题”,在每次迭代后记录总数时值得注意。第一个不匹配出现第一个负数,
d=-0.5078606970338732
,a
减少了51
(a+=d*100
),而b
减少了50
(b+=(long)(100*d)
)…结论:long
和double
使用不同的“舍入规则”关于负数。。。证明:…某处:“…如果升级类型为int或long,则执行整数运算。如果升级类型为float或double,则执行浮点运算…”大家干得好!问得好!另一方面,如果右边是浮点数,我绝对不会想到a | b会被转换成浮点数。我认为这很不现实,但我猜它在规范中的某个地方。