现代系统中的定点运算

fixed point arithmetic in modern systems

首先我想说这与优化无关,所以请不要拖延这个主题。我使用定点运算的目的是因为我想在不使用浮点的情况下控制我的计算精度。

话虽如此,让我们继续前进。我想要 17 位用于范围,15 位用于小数部分。额外的位用于带符号的值。下面是一些宏。

const int scl = 18;
#define Double2Fix(x) ((x) * (double)(1 << scl))
#define Float2Fix(x) ((x) * (float)(1 << scl))
#define Fix2Double(x) ((double)(x) / (1 << scl))
#define Fix2Float(x) ((float)(x) / (1 << scl))

加法和减法相当简单,但使用 mul 和 div 时事情变得有点棘手。

我见过两种不同的方法来处理这两种类型的操作。 1) 如果我使用 32 位,则使用临时 64 位变量来存储中间乘法步骤,然后在最后缩放。

2) 就在乘法步骤中,在乘法之前将两个变量缩放到较小的位范围。例如,如果您有一个 32 位寄存器,其中 16 位用于表示整数,您可以这样移位:

(((a)>>8)*((b)>>6) >> 2) or some combination that makes sense for you app.

在我看来,如果您围绕 32 位设计定点数学,那么始终依赖于能够存储中间值的 64 位变量可能是不切实际的,但另一方面,转移到较低的比例会严重减少你的范围和精度。

问题 由于我想避免尝试强制 cpu 在我的计算过程中尝试创建 64 位类型是唯一的其他选择吗?

我也注意到了

    int b = Double2Fix(9.1234567890);
    printf("double shift:%f\n",Fix2Double(b));

    int c = Float2Fix(9.1234567890);
    printf("float  shift:%f\n",Fix2Float(c));

    double shift:9.123444
    float  shift:9.123444

精度损失只是使用定点数的一部分吗?

Since i'd like to avoid trying to force the cpu to try to create a 64bit type in the middle of my calculations is the shifting to lower bit values the only other alternative?

您必须使用硬件功能,您会发现唯一可用的操作是:

  1. 乘以 N x N => 低 N 位(原生 C 乘法)
  2. 乘N x N =>高N位(C语言没有这方面的运算符)
  3. 乘以 N x N => 所有 2N 位(转换为更宽的类型,然后相乘)

如果指令集有#3,并且 CPU 有效地实现了它,则无需担心它产生的超宽结果。对于 x86,您几乎可以将这些视为给定的。无论如何,你说这不是一个优化问题:) .

坚持#1,您需要将操作数分成 (N/2) 位的片段并进行长乘法,这可能会产生更多的工作。在某些情况下,这样做是正确的,例如在没有它的 CPU 或 #2.

上实现 #3(软件扩展算术)

Is that precision loss just a part of using fixed point numbers?

log2( 9.1234567890 – 9.123444 ) = –16.25,并且您使用了 16 位精度,所以是的,这非常典型。