2个相同比例的数字相除结果总是相同的吗?
Will division result of 2 numbers with the same ratio always be the same?
a
是一个 integer
.
b
也是一个 integer
,但声明为 double
。
c = a/b
,并且 c
也声明为 double
。
还有a2
、b2
、c2
,规则与a
、b
、c
相似。
另外,在十进制代数方面,2组数满足: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
).
总结
是,如果:
a
和a2
是32位整数,
b
和 b2
是非零 Java double
值,并且
a
/ b
= a2
/ b2
,
然后 a / b
等于 a2 / b2
。 (注意 a
/ b
表示实数运算,而 a / b
表示浮点运算。 4
/ 3
正好是 1⅓,而 4./3
是 1.3333333333333332593184650249895639717578887939453125。)
证明
根据作者的评论,这是针对 Java,它使用 IEEE 754,包括 double
的 IEEE-754 基本 64 位二进制浮点数。
大多数浮点运算的一个基本属性是,计算结果是四舍五入到浮点格式可表示的最接近值的实数结果。结果是:
- 如果两个运算有相同的实数结果并使用相同的舍入规则,则它们有相同的浮点数结果。
(有各种舍入规则。Java 使用 round-to-nearest-ties-to-even,意思是使用最接近的可表示值,如果有平局,则与使用偶数低位。)
另一个结果是:
- 如果运算的实数结果可以浮点格式表示,则为浮点结果。 (没有舍入误差。)
现在让我们考虑表达式 a / b
和 a2 / b2
。由于混合类型,每个中的第一步是分别将 a
或 a2
从其整数类型转换为 double
。这个问题告诉我们假设整数类型有 32 位。所有 32 位整数都可以在 double
中精确表示(因为 double
具有 53 位有效数字)。转换值的数学结果当然是值本身,因为转换旨在更改类型,而不是值。因此,将a
或a2
转换为double
的结果分别正好是a
或a2
。
接下来是除法,a / b
或a2 / b2
。我们被告知 a
/ b
= a2
/ b2
。这告诉我们 a / b
的实数结果等于 a2 / b2
的实数结果。由于这两个运算的实数结果相同,使用相同的舍入规则,所以它们的浮点数结果相同。
讨论
以上的一些限制是:
- 如果
a
或 a2
可能超过 53 位,则它可能具有无法在 double
中表示的值。那么将其转换为double
的操作就得对其取整了。四舍五入可能会以不同方式影响 a
和 a2
,然后商 a / b
和 a2 / b2
可能会不同。
- 一些编程语言对如何执行浮点运算并不严格,并且它们不符合 IEEE-754 规则。我相信以上内容适用于 Java,但 C 或 C++ 中可能存在问题。
请注意,b
和 b2
可能非常小(包括零)以致商溢出,计算结果为无穷大。尽管如此,a
/ b
= a2
/ b2
的事实将要求两个结果都是无穷大或两者都不是 - 浮点结果等于实数的规则数字结果仍然相等。
如果 a
、a2
、b
和 b2
为零,则两个运算都会产生 NaN,但两个 NaN 不会比较相等。
如果 a
和 a2
不为零但 b
和 b2
为零,则这两个操作都会产生无穷大。符号将是分子和除数符号的 XOR。这意味着即使 a
= a2
和 b
= b2
,a / b
和 a2 / b2
也会产生不同的无穷大(一个正数,一个负数) ,因为 IEEE-754 有 +0 和 −0,它们比较相等但符号不同。
a
是一个 integer
.
b
也是一个 integer
,但声明为 double
。
c = a/b
,并且 c
也声明为 double
。
还有a2
、b2
、c2
,规则与a
、b
、c
相似。
另外,在十进制代数方面,2组数满足: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
).
总结
是,如果:
a
和a2
是32位整数,b
和b2
是非零 Javadouble
值,并且a
/b
=a2
/b2
,
然后 a / b
等于 a2 / b2
。 (注意 a
/ b
表示实数运算,而 a / b
表示浮点运算。 4
/ 3
正好是 1⅓,而 4./3
是 1.3333333333333332593184650249895639717578887939453125。)
证明
根据作者的评论,这是针对 Java,它使用 IEEE 754,包括 double
的 IEEE-754 基本 64 位二进制浮点数。
大多数浮点运算的一个基本属性是,计算结果是四舍五入到浮点格式可表示的最接近值的实数结果。结果是:
- 如果两个运算有相同的实数结果并使用相同的舍入规则,则它们有相同的浮点数结果。
(有各种舍入规则。Java 使用 round-to-nearest-ties-to-even,意思是使用最接近的可表示值,如果有平局,则与使用偶数低位。)
另一个结果是:
- 如果运算的实数结果可以浮点格式表示,则为浮点结果。 (没有舍入误差。)
现在让我们考虑表达式 a / b
和 a2 / b2
。由于混合类型,每个中的第一步是分别将 a
或 a2
从其整数类型转换为 double
。这个问题告诉我们假设整数类型有 32 位。所有 32 位整数都可以在 double
中精确表示(因为 double
具有 53 位有效数字)。转换值的数学结果当然是值本身,因为转换旨在更改类型,而不是值。因此,将a
或a2
转换为double
的结果分别正好是a
或a2
。
接下来是除法,a / b
或a2 / b2
。我们被告知 a
/ b
= a2
/ b2
。这告诉我们 a / b
的实数结果等于 a2 / b2
的实数结果。由于这两个运算的实数结果相同,使用相同的舍入规则,所以它们的浮点数结果相同。
讨论
以上的一些限制是:
- 如果
a
或a2
可能超过 53 位,则它可能具有无法在double
中表示的值。那么将其转换为double
的操作就得对其取整了。四舍五入可能会以不同方式影响a
和a2
,然后商a / b
和a2 / b2
可能会不同。 - 一些编程语言对如何执行浮点运算并不严格,并且它们不符合 IEEE-754 规则。我相信以上内容适用于 Java,但 C 或 C++ 中可能存在问题。
请注意,b
和 b2
可能非常小(包括零)以致商溢出,计算结果为无穷大。尽管如此,a
/ b
= a2
/ b2
的事实将要求两个结果都是无穷大或两者都不是 - 浮点结果等于实数的规则数字结果仍然相等。
如果 a
、a2
、b
和 b2
为零,则两个运算都会产生 NaN,但两个 NaN 不会比较相等。
如果 a
和 a2
不为零但 b
和 b2
为零,则这两个操作都会产生无穷大。符号将是分子和除数符号的 XOR。这意味着即使 a
= a2
和 b
= b2
,a / b
和 a2 / b2
也会产生不同的无穷大(一个正数,一个负数) ,因为 IEEE-754 有 +0 和 −0,它们比较相等但符号不同。