C中浮点数上的定点运算的位移

时间:2012-05-30 15:28:53

标签: c floating-point bit-shift fixed-point

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

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 个答案:

答案 0 :(得分:3)

如果您想使用固定点,请不要使用“float”或“double”类型,因为它们具有内部结构。浮标和双打有特定的符号位;一些用于指数的位,一些用于尾数(看一下彩色图像here);所以他们天生就是浮点。

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

GCC中实现了浮点扩展的说明:http://gcc.gnu.org/onlinedocs/gcc/Fixed_002dPoint.html

C:http://www.eetimes.com/discussion/other/4024639/Fixed-point-math-in-C

有一些基于MACRO的定点手动实现

答案 1 :(得分:2)

你正在做的事情是数字的残酷。

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

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,应该在&gt;&gt;再次增加1,3.0之后。我不知道为什么不是,可能是因为我在这里犯了错误。

留下的是你不能对浮子进行位移,期望得到可靠的结果。

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

答案 2 :(得分:2)

您的编译器可能使用IEEE 754格式的float s,在位方面,它看起来像这样:

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做同样的事情,但是你可能会认为移动只是搞砸浮点数。

答案 3 :(得分: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);
  }