返回资讯中心
外部精选
软件工程
#社区热议

VHDL标准浮点包 ieee.float_pkg 算错 sqrt(2) 等多个结果

来源标题:The VHDL standard's float package gets sqrt(2) wrong

VHDL 标准(IEEE 1076-2008/2019)自带的 floating-point 包 ieee.float_pkg 存在计算错误,sqrt(2.0) 在 float64 下返回 3FF6A09E667F3BCC,而正确舍入结果应为 3FF6A09E667F3BCD。GHDL 7.0.0-dev 与 NVC 1.23.1 原样分发该实现,在相同测试向量下输出一致。mac 与 resize 等调用同样与精确算术参考结果不符。

Hacker Newslmtlssss2026/11/14 · 今天30 分钟阅读

以下正文由 AI 翻译自 Hacker News(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

ieee.float_pkg 是 VHDL 标准(IEEE Std 1076-2008 和 1076-2019)的浮点运算包。源码来自 IEEE 官方:opensource.ieee.org/vasg/Packages 发布分支上的 ieee/float_generic_pkg-body.vhdl,共 5,712 行,$Revision: 1220 $。gitlab.com/IEEE-P1076/Packages 上工作组 develop 分支的字节内容与之相同,GHDL 和 NVC 原样发布。此处运行使用 GHDL 7.0.0-dev 和 NVC 1.23.1,两者对相同测试向量运行时会写出相同的结果文件。

该包与精确算术进行对比。一个操作数由一个符号和两个整数构成的小数表示,运算在小数上进行,结果按调用指定的舍入方式一次性舍入为目标格式。exact.py 就是这一参考实现。

使用该包自身的设置:round_nearest、3 个保护位、启用非规格化数。

调用 返回精确舍入结果 sqrt (2.0) 在 float64 中 3FF6A09E667F3BCC 3FF6A09E667F3BCD sqrt (14.0) 406F7750 406F7751 sqrt (2.0**-149) 4.2e-22 3.7e-23 mac (-6.0, -1.0, -5.0) -15.0 1.0 mac (-5.0, 1.0, 4.0) 15.0 -1.0 mac (1.0, 1.0, -infinity) +infinity -infinity mac (1 + 2.0**-23, 1 - 2.0**-23, -1.0) -2.0**-26 -2.0**-46 resize (float64 中的 2.0**-512, 8, 23) 1.0 0.0 resize (float64 中的 2.0600, 8, 23) 2.088 +infinity resize (float64 中的 2.0**-1074, 8, 23) +infinity 0.0 resize (float64 中的 2.0**-650, 8, 23) 使模拟器停止 0.0 reciprocal (2.0127) +infinity 2.0-127 divide (2.0**-149, 2.0) 2.0**-149 0.0 dividebyp2 (3 * 2.0**-149, 2.0) 2.0**-149 2.0**-148 scalb (1.0, 300) 0.0 +infinity scalb (+infinity, -10) 2.0**118 +infinity to_signed (0.50000006, 32) 0 1 to_unsigned (199.78125, 8) 199 200

以及调用指定舍入方式的情况: divide (6.0, 3.0, round_inf) 2.0000002 2.0 reciprocal (2.0, round_inf) 0.50000006 0.5 add (largest, largest, round_zero) +infinity largest multiply (2.0**-100, 2.0**-100, round_inf) 0.0 2.0**-149 add (1.0, -1.0, round_neginf) +0.0 -0.0 to_signed (2.25, 8, round_inf) 2 3 to_float (100000, 5, 10, round_zero) +infinity 65504.0,即最大值

plain.vhd 进行这些调用,并在每个不等于精确舍入结果的结果旁打印 WRONG:共 24 行,第 25 个调用在包体第 358 行因索引越界使模拟器停止。只需 GHDL 即可运行: ghdl -a --std=08 plain.vhd ghdl --elab-run --std=08 plain

这些普通操作数并不罕见。在 1 到 4,096 的整数中,sqrt 对其中 256 个返回偏差一个单位的 float32 结果,对 264 个返回偏差一个单位的 float64 结果。在由 -6 到 6、0.25、0.5、1.5 和 10 构成的 4,913 个三元组中,mac 对其中 290 个返回错误的 float32。从 float64 到 float32 的 resize 对从 2^-1074 到 2^-1024 的每个 2 的幂返回 +infinity,从 2^-662 到 2^-639 使模拟器停止,从 2^-638 到 2^-512 返回 2^(e+512),从 2^513 到 2^639 返回 2^(e-512)。

每种操作、格式和舍入方式各 10,000 次调用,操作数针对算术容易出错的场景:非规格化操作数和结果、指数范围的两端、向上舍入进入下一个 binade 的小数、精确平局、带符号零、无穷大。单元格中是不等于精确舍入结果的结果数量,占所比较调用的比例。结果不适合整数的转换不参与比较。

float32 round_nearest round_zero round_neginf round_inf add 0 / 10,000 304 / 10,000 312 / 10,000 159 / 10,000 subtract 0 / 10,000 314 / 10,000 312 / 10,000 143 / 10,000 multiply 0 / 10,000 1,102 / 10,000 781 / 10,000 775 / 10,000 divide 27 / 10,000 670 / 10,000 2,324 / 10,000 2,395 / 10,000 sqrt 735 / 10,000 581 / 10,000 542 / 10,000 774 / 10,000 mac 2,671 / 10,000 3,697 / 10,000 3,213 / 10,000 3,302 / 10,000 reciprocal 384 / 10,000 586 / 10,000 1,093 / 10,000 2,613 / 10,000 resize 到更窄格式 422 / 20,000 2,728 / 20,000 2,516 / 20,000 2,466 / 20,000 另有 272 次使模拟器停止 resize 到更宽格式 0 / 20,000 0 / 20,000 0 / 20,000 0 / 20,000 to_float(有符号,32 和 64 位) 0 / 20,000 0 / 20,000 0 / 20,000 0 / 20,000 to_signed(8、32、64 位) 613 / 28,637 0 / 28,626 5,934 / 28,608 5,898 / 28,623 to_unsigned(8、32、64 位) 280 / 16,506 0 / 17,133 0 / 14,493 5,964 / 17,145 to_integer 0 / 10,000 0 / 10,000 1,921 / 10,000 1,973 / 10,000 to_float(整数) 0 / 10,000 0 / 10,000 0 / 10,000 0 / 10,000 dividebyp2 1,542 / 10,000 1,904 / 10,000 2,313 / 10,000 2,262 / 10,000 scalb 2,653 / 10,000 3,088 / 10,000 3,381 / 10,000 3,401 / 10,000 float64 round_nearest round_zero round_neginf round_inf add 0 / 10,000 260 / 10,000 311 / 10,000 138 / 10,000 subtract 0 / 10,000 283 / 10,000 317 / 10,000 147 / 10,000 multiply 0 / 10,000 1,163 / 10,000 852 / 10,000 866 / 10,000 divide 18 / 10,000 698 / 10,000 2,495 / 10,000 2,406 / 10,000 sqrt 1,278 / 10,000 619 / 10,000 659 / 10,000 799 / 10,000 mac 2,673 / 10,000 3,697 / 10,000 3,285 / 10,000 3,290 / 10,000 reciprocal 350 / 10,000 477 / 10,000 1,087 / 10,000 2,623 / 10,000 resize 到更窄格式 801 / 30,000 4,116 / 30,000 3,980 / 30,000 4,014 / 30,000 另有 445 次使模拟器停止 resize 到更宽格式 0 / 10,000 0 / 10,000 0 / 10,000 0 / 10,000 to_float(有符号,32 和 64 位) 0 / 20,000 0 / 20,000 0 / 20,000 0 / 20,000 to_signed(8、32、64 位) 618 / 28,219 0 / 28,231 6,161 / 28,340 5,952 / 28,262 to_unsigned(8、32、64 位) 321 / 16,330 0 / 16,839 0 / 14,237 6,155 / 16,776 to_integer 0 / 10,000 0 / 10,000 2,125 / 10,000 2,183 / 10,000 to_float(整数) 0 / 10,000 0 / 10,000 0 / 10,000 0 / 10,000 dividebyp2 1,543 / 10,000 1,902 / 10,000 2,321 / 10,000 2,391 / 10,000 scalb 2,218 / 10,000 2,540 / 10,000 2,982 / 10,000 2,967 / 10,000

在 float32 中,即 859,771 次调用中有 81,068 次错误、272 次停止;在 float64 中,857,234 次调用中有 86,081 次错误、445 次停止。同样的调用在 float16 中 866,782 次有 113,980 次错误,在 float128 中 855,777 次有 90,744 次错误、585 次停止。

当格式足够小时,其中的每个操作数都进行测试: 格式 调用数 比较数 错误数

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →