Main Content

定点算术

加减法

定点数的加法要求加数的二进制小数点对齐。然后使用二进制算术执行加法,不使用 0 或 1 以外的数字。

以将 010010.1 (18.5) 与 0110.110 (6.75) 相加为例:

010010.1+0110.110¯011001.010(18.5)(6.75)(25.25)

定点减法相当于使用任何负值的 2 的补码值进行相加。在减法中,加数必须经过符号扩展以匹配彼此的长度。以从 010010.1 (18.5) 中减去 0110.110 (6.75) 为例:

010010.1000110.110¯(18.5)(6.75)

默认的全局 fimath 配置的 CastBeforeSum 属性值为 1 (true)。这会在相加之前将加数转换为加和数据类型。因此,在相加过程中无需进一步移位来对齐二进制小数点。

如果 CastBeforeSum 的值为 0 (false),则加数相加时保持完整的精度。执行加法后,对和进行量化。

乘法

2 的补码定点数的乘法与普通小数乘法几乎完全一样,只是中间结果必须经过符号扩展,以便在它们相加之前将其左侧对齐。

以 10.11 (-1.25) 与 011 (3) 的乘法为例:

乘法数据类型

下列各图显示使用 Fixed-Point Designer™ 软件进行定点乘法所用的数据类型。这些图说明了实数与实数、复数与实数以及复数与复数之间乘法所用的数据类型之间的差异。

实数与实数的乘法.  下图显示在两个实数之间的乘法中工具箱使用的数据类型。软件以乘积的数据类型返回此运算的输出,该数据类型由 fimath 对象的 ProductMode 属性确定。

实数与复数之间的乘法.  下图显示在实数与复数定点数之间的乘法中工具箱使用的数据类型。实数与复数之间的乘法和复数与实数之间的乘法是等同的。软件以乘积的数据类型返回此运算的输出,该数据类型由 fimath 对象的 ProductMode 属性确定:

复数与复数之间的乘法.  下图显示两个复数定点数的乘法。请注意,软件以加和数据类型返回此运算的输出,该数据类型由 fimath 对象 SumMode 属性确定。中间乘积的数据类型由 fimath 对象的 ProductMode 属性确定。

fimath 对象的 CastBeforeSum 属性为 true 时,在上图中的乘数后将转换为加和数据类型。在 C 代码中,对于减法器,这相当于

acc=ac;
acc-=bd;

对于加法器,相当于

acc=ad;
acc+=bc;

其中 acc 是累加器。当 CastBeforeSum 属性为 false 时,转换不存在,并且在减法和加法运算之前数据仍为乘积的数据类型。

与 fimath 相乘

在以下示例中,基于如下条件:

F = fimath('ProductMode','FullPrecision',...
'SumMode','FullPrecision');
T1 = numerictype('WordLength',24,'FractionLength',20);
T2 = numerictype('WordLength',16,'FractionLength',10);

实数与实数相乘.  请注意,结果 z 的字长和小数长度分别等于各被乘数的字长和小数长度之和。这是因为 fimath SumModeProductMode 属性设置为 FullPrecision

P = fipref;
P.FimathDisplay = 'none';
x = fi(5,T1,F)
x = 

     5

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 24
        FractionLength: 20
y = fi(10,T2,F)
y = 

    10

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 10
z = x*y
z = 

    50

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 40
        FractionLength: 30

实数与复数相乘.  请注意,结果 z 的字长和小数长度分别等于各被乘数的字长和小数长度之和。这是因为 fimath SumModeProductMode 属性设置为 FullPrecision

x = fi(5,T1,F)
x = 

     5

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 24
        FractionLength: 20
y = fi(10+2i,T2,F)
y = 

  10.0000 + 2.0000i

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 10
z = x*y
z = 

  50.0000 +10.0000i

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 40
        FractionLength: 30

复数与复数相乘.  复数与复数的乘法涉及加法和乘法,因此全精度结果的字长比各被乘数的字长之和还要多一位:

x = fi(5+6i,T1,F)
x = 

   5.0000 + 6.0000i

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 24
        FractionLength: 20
y = fi(10+2i,T2,F)
y = 

  10.0000 + 2.0000i

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 10
z = x*y
z = 

  38.0000 +70.0000i

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 41
        FractionLength: 30

模算术

二进制数学计算基于模算术。模算术仅使用有限数字集合,超出给定集合的任何计算结果会绕回到该集合。

例如,普通的日常钟表使用模 12 算术。此系统中的数字只能是 1 到 12。因此,在“时钟”系统中,9 加 9 等于 6。以数字环形式可以更直观地表示为如下:

同样,二进制数学只能使用数字 0 和 1,超出此范围的任何算术结果都将以“绕环”形式绕回为 0 或 1。

2 的补码

2 的补码是解释二进制数字的一种方式。在 2 的补码中,正数始终以 0 开头,负数始终以 1 开头。如果 2 的补码数的前导位为 0,则通过计算该数的标准二进制值来获得该值。如果 2 的补码数的前导位是 1,则通过假设最左侧位是负数然后计算该数的二进制值来获得该值。例如,

01=(0+20)=111=((21)+(20))=(2+1)=1

要使用 2 的补码计算二进制数的负数,请执行下列操作:

  1. 获得 1 的补码,即“翻转位”。

  2. 按二进制数学计算方式加 2^(-FL),其中 FL 是小数长度。

  3. 丢弃超出原始字长的任何位。

以获得 11010 (-6) 的负数为例。首先,获得该数的 1 的补码(即翻转位):

1101000101

接下来,加 1,将所有数字绕回为 0 或 1:

00101+1¯00110(6)

转换

fimath 对象允许您使用 SumModeProductMode 属性指定中间求和与乘积的数据类型和定标。当您设置 SumModeProductMode 属性时,务必考虑每种转换会产生的影响。根据您选择的数据类型,可能会发生溢出和/或舍入。以下两个示例说明可能发生溢出和舍入的情况。

注意

有关转换的更多示例,请参阅Cast fi Objects

从较短的数据类型转换为较长的数据类型

考虑将具有两个小数位的 4 位数据类型表示的非零数字转换为具有七个小数位的 8 位数据类型:

如上图所示,源位向上移位,以使二进制小数点与目标二进制小数点位置匹配。最高的源位无法容纳,因此可能会发生溢出,结果可能会进行饱和或绕回处理。目标数据类型低端的空位用 0 或 1 填充:

  • 如果没有发生溢出,空位将用 0 填充。

  • 如果发生绕回,空位将用 0 填充。

  • 如果发生饱和,

    • 正数的空位用 1 填充。

    • 负数的空位用 0 填充。

您可以看到,即使从较短的数据类型转换为较长的数据类型,仍然会发生溢出。当源数据类型的整数长度(本例中为 2)长于目标数据类型的整数长度(本例中为 1)时,会发生这种情况。同样,如果目标数据类型和定标的小数位小于源的小数位,则即使在从较短数据类型转换为较长数据类型时也可能需要舍入。

从较长的数据类型转换为较短的数据类型

考虑将具有七个小数位的 8 位数据类型表示的非零数字转换为具有两个小数位的 4 位数据类型:

如上图所示,源位向下移位,以使二进制小数点与目标二进制小数点位置匹配。来自源的最高位没有值,因此使用符号扩展填充目标数据类型的整数部分。符号扩展是将具有最高有效位值的位加到 2 的补码数的高端;符号扩展不更改二进制数的值。目标的小数长度不能容纳源的低端五位。因此,在对结果进行舍入后,精度可能会有一定丢失。

在这种情况下,即使转换是从较长数据类型到较短数据类型,所有整数位都会保留。相反,只要目标数据类型的小数长度等于或大于源数据类型的小数长度,即使转换为较短的数据类型,也可以保持全精度。但是,在这种情况下,结果的高端会丢失位并可能发生溢出。

当目标数据类型的整数长度和小数长度都短于源数据类型和定标的对应长度时,会出现最差情况。在这种情况下,会同时发生溢出和精度损失。