32 位定点运算 1x1 不等于 1
32-bit fixed point arithmetic 1x1 does not equal 1
我正在实现 32 位有符号整数定点运算。 scale是从1到-1,INT32_MAX
对应1,不知道是让INT32_MIN
还是-INT32_MAX
对应-1,暂且搁置。
我做了一些乘法和舍入操作,如下:
#define mul(a, b) ((int64_t)(a) * (b))
#define round(x) (int32_t)((x + (1 << 30)) >> 31)
然后可以使用 round(mul(a, b))
.
求出两个数的乘积
检查身份时出现问题。
主要问题是 1x1 不是 1。它是 INT32_MAX-1
。这显然不是我想要的,因为我想要位精度。我想这会影响附近的其他数字,因此如果操作数都是 INT32_MAX
,则修复不是仅加 1 的情况。
此外,-1x-1 不是 -1,1x-1 不是 -1,并且 -1x-1=-1。所以 none 的身份成立。
是否有简单的解决方法,或者这只是使用定点运算的症状?
在其一般形式中,定点格式将数字 x 表示为整数 x•s 。通常,s是某个基b的幂,s = bp。例如,我们可能将一些美元 x 存储为 x•100,那么 $3.45 可能存储为 345。这里我们很容易看出原因这被称为“定点”格式:存储的数字在概念上将小数点插入固定位置,在这种情况下,最右边数字左边两位:“345”在概念上是“3.45”。 (这也可以称为小数点而不是小数点,允许基数 b 不是十的情况。并且 p 指定在哪里小数点被插入,p base-b 数字从右边开始。)
如果你让INT_MAX
代表1,那么你就是在隐含地说s = INT_MAX
。 (并且,由于 INT_MAX
不是任何其他整数的幂,我们有 b = INT_MAX
和 p = 1.) 则−1 必须表示为−1•INT_MAX
= -INT_MAX
。它不会由 INT_MIN
表示(除了在古老的 C 实现中 INT_MIN
= -INT_MAX
)。
给定 s = INT_MAX
,移位 31 位不是实现乘法的正确方法。给定两个数字 x 和 y,表示为 a 和 b,xy 的表示是通过将表示 a 和 b 相乘并除以 s:
- a表示x,所以a=xs.
- b表示y,所以b=ys.
- 然后ab/s = xsys/s = xys,而xys代表xy.
移位 31 除以 231,因此这与除以 INT_MAX
不同。此外,除法在硬件上通常很慢。您最好选择 s = 230 而不是 INT_MAX
。然后你可以移动 30 位。
在计算ab/s的时候,我们经常会想要四舍五入。在除法之前将 ½s 添加到产品中是一种舍入方法,但它可能不是您想要的负产品。如果乘积为负,您可能需要考虑添加 −½s。
我正在实现 32 位有符号整数定点运算。 scale是从1到-1,INT32_MAX
对应1,不知道是让INT32_MIN
还是-INT32_MAX
对应-1,暂且搁置。
我做了一些乘法和舍入操作,如下:
#define mul(a, b) ((int64_t)(a) * (b))
#define round(x) (int32_t)((x + (1 << 30)) >> 31)
然后可以使用 round(mul(a, b))
.
检查身份时出现问题。
主要问题是 1x1 不是 1。它是 INT32_MAX-1
。这显然不是我想要的,因为我想要位精度。我想这会影响附近的其他数字,因此如果操作数都是 INT32_MAX
,则修复不是仅加 1 的情况。
此外,-1x-1 不是 -1,1x-1 不是 -1,并且 -1x-1=-1。所以 none 的身份成立。
是否有简单的解决方法,或者这只是使用定点运算的症状?
在其一般形式中,定点格式将数字 x 表示为整数 x•s 。通常,s是某个基b的幂,s = bp。例如,我们可能将一些美元 x 存储为 x•100,那么 $3.45 可能存储为 345。这里我们很容易看出原因这被称为“定点”格式:存储的数字在概念上将小数点插入固定位置,在这种情况下,最右边数字左边两位:“345”在概念上是“3.45”。 (这也可以称为小数点而不是小数点,允许基数 b 不是十的情况。并且 p 指定在哪里小数点被插入,p base-b 数字从右边开始。)
如果你让INT_MAX
代表1,那么你就是在隐含地说s = INT_MAX
。 (并且,由于 INT_MAX
不是任何其他整数的幂,我们有 b = INT_MAX
和 p = 1.) 则−1 必须表示为−1•INT_MAX
= -INT_MAX
。它不会由 INT_MIN
表示(除了在古老的 C 实现中 INT_MIN
= -INT_MAX
)。
给定 s = INT_MAX
,移位 31 位不是实现乘法的正确方法。给定两个数字 x 和 y,表示为 a 和 b,xy 的表示是通过将表示 a 和 b 相乘并除以 s:
- a表示x,所以a=xs.
- b表示y,所以b=ys.
- 然后ab/s = xsys/s = xys,而xys代表xy.
移位 31 除以 231,因此这与除以 INT_MAX
不同。此外,除法在硬件上通常很慢。您最好选择 s = 230 而不是 INT_MAX
。然后你可以移动 30 位。
在计算ab/s的时候,我们经常会想要四舍五入。在除法之前将 ½s 添加到产品中是一种舍入方法,但它可能不是您想要的负产品。如果乘积为负,您可能需要考虑添加 −½s。