双变量的算术运算是否保持整数值?

时间:2011-03-11 12:21:43

标签: java math precision

假设我在double变量中存储了两个整数值,例如: G:

double x = 100.0;
double y = 7.0;

我可以安全地假设对这两个产生整数结果的双变量的任何算术运算都会返回一个精确的整数值(作为double)吗?也就是说,例如所有:

x + y = 107.0
x - y = 93.0
x * y = 700.0

返回确切的整数值,还是会出现一些准确性问题?像x*y那样699.99995左右?

一般性问题:对两个保存整数值的双变量的任何算术运算是否都会产生整数结果?是否会返回精确的整数值(作为double)?

我在Java环境中问这个问题,但我认为它在其他语言中也是如此。

7 个答案:

答案 0 :(得分:12)

只要操作的整数结果可以精确地表示为double,就会得到精确的结果,但只要整数结果超过尾数中可用的位数(即52 + 1 = 53)比特),它将被舍入。

答案 1 :(得分:4)

总的来说,答案是否定的。但是,我强烈建议阅读David Goldberg的"What Every Computer Scientist Should Know About Floating-Point Arithmetic" - 从内部了解事情从不会伤害。

答案 2 :(得分:3)

如果结果数字的位数太多而不适合double,则不会。例如,1234567890.0 * 1234567890.0产生1,52415787501905E+18而不是1524157875019052100。如果结果合适,我不知道它是否总是精确的,但是@Sven Marnach回答了这个问题。我假设截断的数字将被一个完全整数关闭,正如@Douglas Leeder所说,因为尾数移动了指数(大于尾数中的位数)将成为一个整数。

答案 3 :(得分:3)

非常好的讨论。

你的问题是

  

任何算术都是如此   操作两个双变量   保持整数值   产生一个整数结果将返回   确切的整数值(作为double)?

我选择了一个临界案例,其中两个数字正好是53位长。 54位总和超过了double的容量,并且它没有返回精确的整数结果。正如预期的那样,低位被截断,你有一个奇怪但预期的结果。

奇数加偶数不会产生奇数(如数学所告诉你的那样); Java报告一个偶数(正如IEEE标准所告诉你的那样)。

试试这个样本:

private static void doubleCalc() {
  double x = 4503599627370497.0d; // binary 10000000000000000000000000000000000000000000000000001
  double y = 4503599627370496.0d; // binary 10000000000000000000000000000000000000000000000000000

  double sum = x + y;
  System.out.println("sum=" + sum + "; should be 9007199254740993.0d");
}

它会打印出来:

sum=9.007199254740992E15; should be 9007199254740993.0d

因此,这个精心挑选的反例会对你措辞谨慎的问题回答“不”。

答案 4 :(得分:2)

所有int值都可以完全由double值表示,+*-操作在这里工作相同(只要你不超过int范围。但/%运算符的工作方式不同。

由于double只有52位尾数,因此您也无法准确表示所有long值。

答案 5 :(得分:1)

只要数字不太远(如2 ^ 1024和0.005),结果应该是准确的。双精度浮点数的工作方式如下:符号为1位,指数为11位,尾数为52位。最终的数字是((-1)* (符号))(1.mantissa<<(exponent-1<< 10))所以当在2个数字之间进行相加时,这就是:

x = number with greatest exponent
y = number with smallest exponent

(in case of same sign)
z.mantissa = x.mantissa + (y.mantissa >> (x.exponent - y.exponent) )
sign = either_one.sign

(in case of opposite sign)
z.mantissa = x.mantissa - (y.mantissa >> (x.exponent - y.exponent) )
sign = x.sign

乘法/除法它有点简单:

z.exponent = x.exponent + y.exponent
z.mantissa = 1.(x.mantissa) (operand) (y.mantissa)
z.sign = x.sign != y.sign
while (z.mantissa is not in format 1.x)
   z.mantissa << 1 (division)
   z.exponent--
   z.mantissa >> 1 (multiplication)
   z.exponent++

所以会发生的是,如果指数相距太远,则在发生移位时会出现数据丢失,这意味着双精度(一般浮点数)的精度不是100%精确(特别是因为某些数字变为周期性的抽取)。然而,对于完美的整数(和结果),只要数字长达52位(尾数的大小)就应该没问题,因为它可以被cpu转换成整数(如1.111 <&lt; 3)是1111)。

答案 6 :(得分:0)

在一个related question中,有人向我指出,一个双精度数大约有15位,而它可以容纳10^(300+)个大数。所以我想只要你使用较小的int就不应该是一个大问题。

这里说的有点来自oracle教程:

  

double:double数据类型是双精度64位IEEE 754浮点。它的值范围超出了本讨论的范围,但在Java语言规范的4.2.3节中有详细说明。对于十进制值,此数据类型通常是默认选择。如上所述,此数据类型不应用于精确值,例如货币。

如需进一步参考,请点击此链接指向上述section 4.2.3

相关问题