IEEE754 分度精度
IEEE754 division precision
来自 IEEE754,我阅读
[...] every operation [...] shall be performed as if it first produced an intermediate
result correct to infinite precision and with unbounded range, and then rounded that
result [...].
我的理解是双1.0108552519184509e+76
(0x4FB6593CEBC97CC5
)除以4.1777521369084075e+147
(0x5E94E917A9CC65DC
),理论上的中间分数部分是
(二进制)
1.0001000110011011000100110000110101001010110111101110100000000000001...
并且应该四舍五入到(舍入模式"nearest")
1.0001000110011011000100110000110101001010110111101111
导致商为 2.41961518728705e-72
(0x311119B130D4ADEF
)。
此处的一个 SW 产生 2.4196151872870495e-72
(0x311119B130D4ADEE
),这似乎表明它只计算特定位置的中间分数,例如
1.000100011001101100010011000011010100101011011110111010000000000
然后四舍五入。
这符合 IEEE754 吗?这是一种常见的方法吗?
有些语言允许更高的精度,这似乎就是这里发生的情况。我使用 Java 的 BigDecimal 将输入的精确表示除以小数点后 1000 位。结果以“2.419615187287049816675514541262468407091280398183303735778952998096290304758722566”开头,稍微接近下边的值
在给定的计算中是否允许额外的精度是语言规范的问题。
一般来说,浮点运算使用保护数字来获得相同的结果,就好像计算是精确完成然后四舍五入一样。为了进行最接近的正常循环,系统需要知道将保留的位之外的一位,以及是否有任何较低有效位为 1 的指示。
在请求澄清后,问题是关于 IEEE 754 的,与编程语言无关。在这种情况下,以“舍入到最近”的方式获得正在考虑的除法的结果 2.4196151872870495e-72
纯粹是不正确的。根据问题中找到的定义,正确的结果是2.41961518728705e-72
:
[...] every operation [...] shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that result [...].
实践中发生的情况是,大多数编程语言实现(通常是规范)并没有过多强调浮点运算严格遵守 IEEE 754 语义。即使当 IEEE 754 双精度表示用于存储浮点值时,操作最终可以实现为:
如果参数不是具有 64 位尾数的 80 位浮点值,转换 从双精度到此格式。这不会丢失精度并且本身不会成为问题
从 80 位操作数计算 80 位结果,因为使用 8087 指令集计算时,这很容易,无需额外努力
之后或之后,转换(换句话说,舍入)80位值将其 64 位有效数转换为具有 53 位有效数的双精度值。
在某些情况下,最后一步不会立即发生,而是在编译器的突发奇想下发生。这特别烦人,因为它使代码具有不确定性。添加不应影响计算的单独调试代码确实会通过更改 80 位寄存器的可用性并导致其中一些溢出并四舍五入为双精度来改变它们。
即使立即对每个中间结果进行双精度存储,仍然存在这样的问题,即结果已计算并正确舍入为 64 位的有效数,然后再次舍入为 53 位。在某些情况下,数学结果接近两个双精度值之间的中点,将其四舍五入到 64 位有效位数将其拖到恰好中间。如果此结果及其 64 位尾数随后舍入为 53 位,则最终结果与直接应用 IEEE 754 规则产生的值不同。只有当数学结果非常接近两个双精度数字之间的中点时才会发生这种情况,因此两个答案几乎都是同样准确的答案,但其中一个是 IEEE 754 标准所说的而不是另一个。
文章The pitfalls of verifying floating-point computations更进一步
正在阅读。
备注:
正如 Patricia 在她的回答中提到的那样,IEEE 754 指定 +、-、*、/ 和 √ 的计算方式应与数学结果(有时具有无限数字)经过计算然后四舍五入的原因相同,原因是存在无需计算整个数学结果即可获得此结果的算法。当已知没有算法可以廉价地获得这种“正确舍入”的结果时,例如对于三角函数,标准不强制要求它。
由于您在解释如何配置 387 FPU 以直接在 53 位有效数字处舍入的页面上找到了解决方案,我应该指出即使在这种配置之后,双舍入问题仍然存在,尽管这种情况要少得多。实际上,虽然 FPU 的有效位可以限制为 53 位,但没有等效的方法来限制指数。即使在 53 位有效数模式下,在 387 上计算时,产生次正规结果的双精度运算也往往会被双舍入。这让我问这个 question about how Java implementations implement multiplication on the 387.
来自 IEEE754,我阅读
[...] every operation [...] shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that result [...].
我的理解是双1.0108552519184509e+76
(0x4FB6593CEBC97CC5
)除以4.1777521369084075e+147
(0x5E94E917A9CC65DC
),理论上的中间分数部分是
(二进制)
1.0001000110011011000100110000110101001010110111101110100000000000001...
并且应该四舍五入到(舍入模式"nearest")
1.0001000110011011000100110000110101001010110111101111
导致商为 2.41961518728705e-72
(0x311119B130D4ADEF
)。
此处的一个 SW 产生 2.4196151872870495e-72
(0x311119B130D4ADEE
),这似乎表明它只计算特定位置的中间分数,例如
1.000100011001101100010011000011010100101011011110111010000000000
然后四舍五入。
这符合 IEEE754 吗?这是一种常见的方法吗?
有些语言允许更高的精度,这似乎就是这里发生的情况。我使用 Java 的 BigDecimal 将输入的精确表示除以小数点后 1000 位。结果以“2.419615187287049816675514541262468407091280398183303735778952998096290304758722566”开头,稍微接近下边的值
在给定的计算中是否允许额外的精度是语言规范的问题。
一般来说,浮点运算使用保护数字来获得相同的结果,就好像计算是精确完成然后四舍五入一样。为了进行最接近的正常循环,系统需要知道将保留的位之外的一位,以及是否有任何较低有效位为 1 的指示。
在请求澄清后,问题是关于 IEEE 754 的,与编程语言无关。在这种情况下,以“舍入到最近”的方式获得正在考虑的除法的结果 2.4196151872870495e-72
纯粹是不正确的。根据问题中找到的定义,正确的结果是2.41961518728705e-72
:
[...] every operation [...] shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that result [...].
实践中发生的情况是,大多数编程语言实现(通常是规范)并没有过多强调浮点运算严格遵守 IEEE 754 语义。即使当 IEEE 754 双精度表示用于存储浮点值时,操作最终可以实现为:
如果参数不是具有 64 位尾数的 80 位浮点值,转换 从双精度到此格式。这不会丢失精度并且本身不会成为问题
从 80 位操作数计算 80 位结果,因为使用 8087 指令集计算时,这很容易,无需额外努力
之后或之后,转换(换句话说,舍入)80位值将其 64 位有效数转换为具有 53 位有效数的双精度值。
在某些情况下,最后一步不会立即发生,而是在编译器的突发奇想下发生。这特别烦人,因为它使代码具有不确定性。添加不应影响计算的单独调试代码确实会通过更改 80 位寄存器的可用性并导致其中一些溢出并四舍五入为双精度来改变它们。
即使立即对每个中间结果进行双精度存储,仍然存在这样的问题,即结果已计算并正确舍入为 64 位的有效数,然后再次舍入为 53 位。在某些情况下,数学结果接近两个双精度值之间的中点,将其四舍五入到 64 位有效位数将其拖到恰好中间。如果此结果及其 64 位尾数随后舍入为 53 位,则最终结果与直接应用 IEEE 754 规则产生的值不同。只有当数学结果非常接近两个双精度数字之间的中点时才会发生这种情况,因此两个答案几乎都是同样准确的答案,但其中一个是 IEEE 754 标准所说的而不是另一个。
文章The pitfalls of verifying floating-point computations更进一步 正在阅读。
备注:
正如 Patricia 在她的回答中提到的那样,IEEE 754 指定 +、-、*、/ 和 √ 的计算方式应与数学结果(有时具有无限数字)经过计算然后四舍五入的原因相同,原因是存在无需计算整个数学结果即可获得此结果的算法。当已知没有算法可以廉价地获得这种“正确舍入”的结果时,例如对于三角函数,标准不强制要求它。
由于您在解释如何配置 387 FPU 以直接在 53 位有效数字处舍入的页面上找到了解决方案,我应该指出即使在这种配置之后,双舍入问题仍然存在,尽管这种情况要少得多。实际上,虽然 FPU 的有效位可以限制为 53 位,但没有等效的方法来限制指数。即使在 53 位有效数模式下,在 387 上计算时,产生次正规结果的双精度运算也往往会被双舍入。这让我问这个 question about how Java implementations implement multiplication on the 387.