1

我编写了以下测试代码来检查定点算术和位移。

void main(){
    float x = 2;
    float y = 3;
    float z = 1;
    unsigned int * px = (unsigned int *) (& x);
    unsigned int * py = (unsigned int *) (& y);
    unsigned int * pz = (unsigned int *) (& z);
    *px <<= 1;
    *py <<= 1;
    *pz <<= 1;
    *pz =*px + *py;
    *px >>= 1;
    *py >>= 1;
    *pz >>= 1;
    printf("%f %f %f\n",x,y,z);
  }

结果是 2.000000 3.000000 0.000000

为什么最后一个数字是 0?我期待看到 5.000000 我想使用某种定点算法来绕过在图像处理应用程序上使用浮点数。将浮点数组转换为整数的最佳/最简单/最有效的方法是什么?上面的“欺骗编译器”是一种强大的解决方法吗?有什么建议么?

4

4 回答 4

3

如果你想使用定点,不要使用类型' float'或' double',因为它们有内部结构。浮点数和双精度数具有特定的符号位;一些位代表指数,一些位代表尾数(看看这里的彩色图像);所以它们本质上是浮点数。

您应该手动编程定点以整数类型存储数据,或者使用一些定点库(或语言扩展)。

有在 GCC 中实现的浮点扩展的描述:http: //gcc.gnu.org/onlinedocs/gcc/Fixed_002dPoint.html

有一些基于 MACRO 的 C 定点手动实现:http ://www.eetimes.com/discussion/other/4024639/Fixed-point-math-in-C

于 2012-05-30T15:36:19.620 回答
2

你所做的是对数字的残酷对待。

首先,将值分配给浮点变量。它们的存储方式取决于系统,但通常使用IEEE 754 格式。所以你的变量内部看起来像

x = 2.0 = 1 * 2^1   : sign = 0, mantissa = 1,   exponent = 1 -> 0 10000000 00000000000000000000000 = 0x40000000
y = 3.0 = 1.5 * 2^1 : sign = 0, mantissa = 1.5, exponent = 1 -> 0 10000000 10000000000000000000000 = 0x40400000
z = 1.0 = 1 * 2^0   : sign = 0, mantissa = 1,   exponent = 0 -> 0 01111111 00000000000000000000000 = 0x3F800000

如果对这些数字进行一些位移操作,就会混淆符号、指数和尾数之间的边界,因此任何事情都可能发生、可能发生并且将会发生。

在你的情况下:

  • 你的 2.0 变成 0x80000000,导致 -0.0,
  • 你的 3.0 变成 0x80800000,导致 -1.1754943508222875e-38,
  • 你的 1.0 变成 0x7F000000,导致 1.7014118346046923e+38。

后者你通过添加 -0.0 和 -1.1754943508222875e-38 来丢失,它变成了后者,即 0x80800000,这应该是,在再次将其 >> 1, 3.0 之后。我不知道为什么不是,可能是因为我在这里犯了一个错误。

剩下的就是你不能对浮点数进行位移以期望得到可靠的结果。

我会考虑将它们转换为 ARM 上的整数或其他定点,然后按原样通过线路发送它们。

于 2012-05-30T15:58:51.290 回答
2

您的编译器很可能对floats 使用 IEEE 754 格式,按位计算,如下所示:

SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
^ bit 31                       ^ bit 0

S是符号位 s = 1 意味着数字是负数。

E位是指数。有 8 个指数位给出 0 - 255 的范围,指数是有偏差的 - 您需要减去 127 才能获得真正的指数。

F位是小数部分,但是,您需要在前面想象一个不可见的 1,因此小数始终为 1.something,您所看到的只是二进制小数位。

数字 2 是 1 x 2 1 = 1 x 2 128 - 127所以编码为

01000000000000000000000000000000

因此,如果您使用位移位将其向右移动,您会得到

10000000000000000000000000000000

按照惯例,在 IEEE754 中是 -0,所以不是将您的数字乘以 2,而是您的班次将其设为零。

数字 3 是 [1 + 0.5] x 2 128 - 127

这表示为

01000000010000000000000000000000

向左移动会给你

10000000100000000000000000000000

这是 -1 x 2 -126或一些非常小的数字。

你可以对 z 做同样​​的事情,但你可能会认为移位只会搞砸浮点数。

于 2012-05-30T16:06:19.273 回答
1

固定点不是这样工作的。你想要做的是这样的:

void main(){
    // initing 8bit fixed point numbers
    unsigned int x = 2 << 8;
    unsigned int y = 3 << 8;
    unsigned int z = 1 << 8;

    // adding two numbers
    unsigned int a = x + y;

    // multiplying two numbers with fixed point adjustment
    unsigned int b = (x * y) >> 8;

    // use numbers
    printf("%d %d\n", a >> 8, b >> 8);
  }
于 2012-05-30T15:44:19.097 回答