为啥不使用基于二进制补码的浮点数?
Posted
技术标签:
【中文标题】为啥不使用基于二进制补码的浮点数?【英文标题】:Why not use a two's complement based floating-point?为什么不使用基于二进制补码的浮点数? 【发布时间】:2019-07-13 06:50:33 【问题描述】:浮点 64、32 和 16 的 IEEE 754 标准使用有符号有效数和有偏指数。作为一名设计硬件架构的学生,对我来说使用二进制补码作为有效数和指数部分更有意义。
例如,32 位(半精度)浮点数定义为第一位表示符号,接下来的 8 位 - 指数(偏置 127),最后 23 位表示尾数。为了实现(负数的)加法/乘法,我们需要将尾数转换为二进制补码并返回。生成的硬件相当复杂。
相反,请考虑前 8 位是否表示指数,后 24 位是否表示尾数,两者都是二进制补码。位移、加法和乘法相对简单,硬件也不那么复杂。此外,我们有一个唯一的零表示有效数(两个零表示有符号位)
我花了几个月的时间寻找这些设计决策的原因,并找到了这些:
-
2 的补码表示更难以比较。
这是真的,我们需要一个加法器(减法器)来比较 2 的补码。但是,对于 GPU 和我自己的基于 FPGA 的 CNN 加速器等流水线架构,我们需要避免可变延迟。逐位迭代地比较有符号表示使得不可能预先确定延迟。在我看来,在这种情况下,减法更好。
-
历史原因:处理 NAN 和 infs
也许我们可以为此分配一到两位。并将有效位设为 23 位。
-
+0 和 -0 为零,这样 1/+0 = +inf 和 1/-0 = -inf
现在这是一个正当的理由。它并不真正适用于我的用例,但我想知道如果他们用额外的一点来实现它会更好。
我的用例
我正在 FPGA 上构建 CNN 加速器。为乘法和加法预先定义延迟并最大限度地降低硬件复杂性对我来说至关重要。我不执行除法,也不必担心 infs 和 NAN。
因此,我决定使用如上所述的二进制补码表示来使用浮点的自定义内部表示。有什么明显的缺点需要注意吗?
【问题讨论】:
您的方法丢失了大量有用的属性,例如非零数的唯一表示,可表示的正数和负数之间的对称性,或者简单的比较(解释为 IEEE 754 浮点数的两个位模式之间的顺序关系是与解释为符号大小整数的那些位模式之间的顺序关系相同,只要浮点数是有限的)。 您能否详细说明这些有用的属性如何转化为更小的硬件复杂性或处理时间? 你认为这些是 IEEE 754 设计者唯一关心的事情吗? 原谅我,我不明白。提出浮点表示的重点是在有限的硬件上表示实数的连续统,并使用最少的硬件对它们执行操作,同时保持最大可能的精度,对吧? 为什么需要将有效位转换为二进制补码才能进行乘法运算?你不会把有效数字当作无符号吗? 【参考方案1】:这是一个经过充分研究的主题, 系统使用 2 的补码浮点表示;通常是那些早于 IEEE-754 的版本,尽管最近的版本也可用。有关此类系统属性的研究,请参阅本文:https://hal.archives-ouvertes.fr/hal-00157268/document
Kahan 本人(IEEE754 标准的设计者)确实认为,具有单独的 +/-0 对于浮点通常用于的近似值很重要,如果浮点 0 结果本质上是正数则很重要或否定的。详情请见https://people.freebsd.org/~das/kahan86branch.pdf。
所以,是的:完全有可能有 2 的补码浮点数;但标准选择了符号幅度表示。无论您选择哪个,有些操作会很容易,有些会更难;对比是最明显的。当然,如果您正在设计自己的硬件,没有什么能阻止您选择最适合您需求的表示形式!特别是,您甚至可以使用所谓的 unum 和 posit,其中指数和有效数字部分不是固定大小,而是取决于您在范围内的位置。见这里:https://www.johndcook.com/blog/2018/04/11/anatomy-of-a-posit-number/
【讨论】:
【参考方案2】:2s 补码用于整数运算的原因是因为它允许相同的硬件和指令用于有符号和无符号运算,只是在如何检测溢出方面略有不同。对于浮点,没有人关心“无符号”浮点,因此如果您在位级别实现它,使用 2s 补码没有任何好处(节省)。我认为使用 2s 补码的唯一优势是,如果您使用的硬件已经具有某种 2s 补码 ALU。
2s 补码在其表示中存在严重的不对称问题(0),如果您尝试在任何需要舍入或可能损失精度的情况下使用它,则会导致各种数学稳定性问题,比如浮点数是常用的。
【讨论】:
以上是关于为啥不使用基于二进制补码的浮点数?的主要内容,如果未能解决你的问题,请参考以下文章
当我使用较小的浮点数时,为啥 sklearn 中的 KNN 实现会变慢?