定点数运算

  • Published2025-06-07 06:12:26

加法和减法

编辑

若要针对二个缩放系数相同的数字相加或相减,直接针对数字运算即可,运算结果也会有相同的缩放系数,因此可以存储在变量中,或是用在后续的运算中。只要运算过程没有算术溢出(也就是运算过程和结果都可以正确的存储),其结果就会是精确的。若二个缩放系数不相同的数字要相加减,需转换到相同的缩放系数,才能相加减。

乘法

编辑

若要将二个定点数相乘,可以直接将其数字相乘,再假设最后积的缩放系数是被乘数和乘数缩放系数的乘积即可。只要没有舍入,也没有运算溢出,结果会是精确的。

例如,要将123(缩放系数1/1000,实际数值是0.123)和25(缩放系数1/10,实际数值是2.5)会得到123×25 = 3075,缩放系数是(1/1000)×(1/10) = 1/10000,因此实际数值是0.3075。另一个例子是将第一个数字和155(缩放系数1/32,实际数值是155/32 = 4.84375)相乘,所得的数字是123×155 = 19065,其缩放系数是(1/1000)×(1/32) = 1/32000,因此实际数值是19065/32000 = 0.59578125。

为了避免溢出,存储乘积的变量长度会比被乘数和乘数的要长,例如被乘数和乘数分别是十进制的二位数,乘积需要用十进制的四位数来存储,才不会溢出。

除法

编辑

若要将二个定点数相除,可以直接将其数字相除,再假设最后商的缩放系数是被除数和除数缩放系数相除后的商即可。一般来说,相除时会出现舍入,因此结果无法完全精确。

例如,3456(缩放系数1/100,实际数值34.56)和1234(缩放系数1/1000,实际数值1.234)相除会得到3456÷1234 = 3(有舍入),其缩放系数为(1/100)/(1/1000) = 10,因此实际数值是30。若第一个数除以155(缩放系数1/32,实际数值155/32 = 4.84375),会得到3456÷155 = 22(有舍入),其缩放系数为(1/100)/(1/32) = 32/100 = 8/25,因此数值为22×32/100 = 7.04。

在结果不精确时,若被除数使用较小的缩放系数,可以缩小(甚至消除)因为舍入产生的误差。例如,r = 1.23,表示为定点数123,缩放系数1/100,而s = 6.25,表示为6250,缩放系数1/1000,相除后的结果是123÷6250 = 0(有舍入),其缩放系数为(1/100)/(1/1000) = 10。若r先转换为缩放系数1/1000000的数字,定点数表示会是1/1000000,其结果会是1,230,000÷625 = 197(有舍入),其缩放系数为1/1000(实际数值是0.197)。其精确值是1.23/6.25 = 0.1968,后者的计算结果比较接近。

缩放系数的调整

编辑

在定点数运算中,常常需要调整定点数的缩放系数,以下是一些可能的原因:

将一数值存到不同缩放系数的变量中。

将二个数值转换为相同的缩放系数,以便相加减或是比较。

一个数值在和其他数值相乘或是相除后,恢复成原来的缩放系数。

要增加除法运算的精度

要确保乘积或是商的缩放系数是像10n或2n,基数的次幂。

要确保运算结果可以在没有溢出的情形下存储在变量内。

为了要减少处理定点数硬件的成本。

若要将缩放系数R的定点数转换为缩放系数S的定点数,整数需要乘以R/S。以1.23(= 123/100)为例,若要从缩放系数R=1/100,转换为缩放系数S=1/1000,整数123要乘以(1/100)/(1/1000) = 10,因此即为1230/1000。

若二个缩放系数都是基数的次幂,调整缩放系数只是除去较低位数的数字,或是在较低位数增加零。不过,此一运算不能改变符号比特,因此需要像算术移位运算一样的方式,延伸其符号比特。

若R不能被S整除(特别是新的缩放系数S比原来的缩放系数R要大),产生的整数需要进行数值修约。

若r和s是定点数,其缩放系数分别为R和S,运算r ← r×s需要将整数相乘,再除以S,所得结果可能会有数值修约,也有可能会溢出。

例如,二个定点数的缩放系数都是1/100,将1.23乘以0.25,其整数相乘是123乘以25,得到3075,而缩放系数是1/10000,为了还原到1/100的缩放系数,3075需乘以1/100,也就是除以100,依数值修约方法的不同,所得结果可能是31(0.31)或是30(0.30)。

而运算r ← r/s需要将整数相除,再乘以S,所得结果可能会有数值修约,也有可能会溢出。

和浮点数的转换

编辑

若要将浮点数转换为定点数,可以将浮点数除以缩放系数S,再修约到最接近的整数。需确认对应的变量有足够的大小存储所得的结果。依缩放系数、变量长度,以及数值大小的不同,转换有可能需要修约。

若要将定点数转换为浮点数,可以将定点数乘以缩放系数S。若整数的绝对值超过224(IEEE单精度浮点数)或253(IEEE双精度浮点数),可能会需要修约。若|S|非常大或是非常小,可能会有溢出或算术下溢(小于可以表示的最小数)的情形。