有一种数字表示形式结合了十进制小数的精确性与二进制格式的精度。这种表示形式称为比例数字(Scaled Numeric)格式,它的运算效率很高,还不需要任何特殊的硬件。
比例数字格式还有一个优点,即可以选择任意基数,不限于十进制。例如,如果使用三进制(基数为3)小数,则将原始输入值乘以3(或3的幂),就可以精确地表示1/3、2/3、4/9、7/27等数值。这是二进制或十进制计数系统无法做到的。
小数的表示需要将原始数值乘以某个用来将小数部分转换为整数的值。例如,要保持小数点后两位小数的精度,则需要将输入值乘以100。1.3 会被转换为130,小数可以像这样用整数值精确地表示。假如所有参与计算的都是这些小数(这些小数都精确到小数点后两位),则可以使用标准的整数算术运算。例如,数值1.5和1.3 将被转换为整数150和130。这两个整数值相加得到280(对应小数2.8)。输出的时候需要将这些数值除以100,商作为小数值的整数部分,余数(必要时零扩展两位)作为小数部分。除了需要编写专门的输入和输出程序来处理100的乘法和除法(以及处理小数点),比例数字方案几乎与常规整数计算一样简单。
如采用上述这种比例数字格式,数字整数部分的范围会受到限制。例如,需要精确到小数点后两位的十进制数(意味着原始数值需要乘以100)能表示的范围为0~42,949,672(无符号),而不是0~4,294,967,296。
当使用比例格式进行加减法时,两个操作数的缩放比例必须相同。如果左操作数乘以100,则右操作数也必须乘以100。例如,如果变量i10缩放比例为10,而变量j100缩放比例为100,则在将这两个数进行加减之前,要么将i10乘以10(按比例放大为100),要么将j100除以10(按比例缩小为10)。这样就可以确保两个操作数的小数点位置相同(注意,字面值常量和变量同样适用)。
乘法和除法运算并不需要在运算之前让操作数的缩放比例相同。但是,运算结束后可能需要对结果进行调整。假设,两个数值i=25(0.25)和j=1(0.01)按比例缩放100达到小数点后两位的精度。如果使用标准整数运算计算k=i*j,得到的结果是25(25×1=25),按照同样的比例缩放为0.25,但结果应为0.0025。运算并没有错误,问题在于乘法运算的原理。实际的计算过程是:
i和j都已经乘以100,所以最终结果的缩放比例实际上是10,000。当将两个数值相乘时,最终得到的数值的缩放比例是 0,000(100×100)而不是100。要解决这个问题,运算完成后需要将结果除以缩放比例。例如,k=(i*j)/100。
除法运算也有同样的问题。假设有数值m=500(5.0)和n=250(2.5),我们想计算k=m/n。我们期望得到的结果是200(2.0,即5.0/2.5)。但实际计算的过程如下:
乍一看似乎是正确的,但是别忘了缩放比例,缩放之后的结果是0.02。我们需要的结果是200(2.0)。带缩放比例的除法最终抵消了结果中的缩放比例。因此,要想得到正确的结果需要计算k=100*m/n。
乘法和除法进一步限制了精度。如果被除数要先乘以100,那么被除数必然比能表示的最大整数小100倍,否则将会发生溢出(导致错误的结果)。同样,当两个按比例缩放的数值相乘时,最终结果必须要比能表示的最大整数值小100倍,否则也将溢出。因此,使用比例数字表示形式时,需要预留更多位或使用较小的数字。