a
是integer
。
b
也是integer
,但声明为double
。
c = a/b
和c
也被声明为double
。
此外,还有a2
,b2
,c2
,其规则与a
,b
,c
类似。
另外,根据十进制代数,两组数字满足:a / b = a2 / b2
,(例如8 / 18.0 = 12 / 27.0
)。
问题是:
c
和c2
会始终完全相同吗?111 / 135.0 = 0.8222222222222222
333 / 405.0 = 0.8222222222222222
(我的猜测是肯定的,因为所有整数都可以用有限的位数表示为二进制,但不能完全确定计算机除法是否会有所不同。)
假设计算机/语言使用32位表示整数,使用64位表示双精度。
(顺便说一句,在编写测试用例时会遇到此问题,不确定仅使用==
就足够了,还是允许使用较小的增量(= (expected - actual) / actual
),例如+/- 0.000001
)。
答案 0 :(得分:4)
是,如果:
a
和a2
是32位整数,b
和b2
是非零的Java double
值,并且a
/ b
= a2
/ b2
,然后a / b
等于a2 / b2
。 (请注意,a
/ b
表示实数算术,而a / b
表示浮点算术。4
/ 3
正好是1⅓,而{{ 1}}是1.3333333333333332593184650249895639717578578939939453125。)
根据作者的评论,这是针对Java的,它使用IEEE 754,其中包括4./3
的IEEE-754基本64位二进制浮点数。
大多数浮点运算的基本属性是计算结果是四舍五入到浮点格式可表示的最接近值的实数结果。其结果是:
(有各种舍入规则。Java使用从最接近的四舍五入关系到四舍五入关系,这意味着使用了最接近的可表示值,如果存在平局,则使用具有低位偶数的候选值)
另一个后果是:
现在让我们考虑表达式double
和a / b
。由于类型不同,每个步骤的第一步是将a2 / b2
或a
分别从其整数类型转换为a2
。这个问题告诉我们假设整数类型具有32位。所有32位整数都可以在double
中精确表示(因为double
具有53位有效数字)。转换值的数学结果当然是值本身,因为转换旨在更改类型,而不是值。因此,将double
或a
转换为a2
的结果分别恰好是double
或a
。
接下来,有一个分隔a2
或a / b
。我们被告知a2 / b2
/ a
= b
/ a2
。这告诉我们b2
的实数结果等于a / b
的实数结果。由于这两个运算具有相同的实数结果,并且使用相同的舍入规则,因此它们的浮点结果是相同的。
上述限制包括:
a2 / b2
或a
可能超过53位,则其值可能无法在a2
中表示。然后,将其转换为double
的操作将需要四舍五入。四舍五入可能会对double
和a
产生不同的影响,然后商a2
和a / b
可能会不同。请注意,a2 / b2
和b
可能很小(包括零),导致商溢出,并且计算结果为无穷大。尽管如此,b2
/ a
= b
/ a2
的事实将要求两个结果都是无穷大或都不是-浮点结果等于实数的规则数字结果相等仍然成立。
如果b2
,a
,a2
和b
为零,则两个操作都将产生NaN,但两个NaN将不相等。>
如果b2
和a
不为零,而a2
和b
为零,则两个操作都将产生无穷大。该符号将是分子和除数的符号的XOR。这意味着即使b2
= a / b
和a2 / b2
= a
,a2
和b
也会产生不同的无穷大(一个正,一个负)。 ,因为IEEE-754的+0和-0都相等,但符号不同。