文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>嵌入式平台上一个浮点处理的问题

嵌入式平台上一个浮点处理的问题

时间:2007-03-05  来源:rockins

嵌入式平台上一个浮点处理的问题

(陈云川 [email protected] UESTC,CD)

1 引言

本文作者在为Sitsang评估板编写一个从二进制文件中读取浮点数的程序时,发现一个奇怪的问题:在x86上编译后能够正确运行的程序,交叉编译后拿到评估板上跑就不对了。比如,本来文件中保存的二进制数据的值应该是6244.760200f,在PC上读出来的值也是对的,但是在评估板上运行时读出来的值就是0.00000f。我首先当然怀疑是字节序的问题,于是写了一个小程序测试了一下PC机和Sitsang评估板的整数的字节序,发现两者的字节序都是小端字节序。我一再地仔细检查了程序逻辑,发现程序在逻辑上应该是没有问题的,于是问题的焦点就落到了Sitsang评估板如何表示浮点数据上。同样地,我写了一个小测试程序,用来测试这一疑点。测试的结果有点出乎意料,一个占据8字节的双精度浮点数,在x86平台上和在Sitsang评估板上的表示是不同的。不同之处在于:在Sitsang评估板上,双精度浮点数的前4个字节和后4个字节恰好与在x86平台上的前4个字节和后4个字节是相反的。而这一点直接导致了问题的发生——因为采用的二进制数据文件是在x86平台上制作完成的。

2 测试程序

测试程序非常简单,如下所示:

#include <stdio.h>

#include <stdlib.h>

int

main(void)

{

    double d = 6244.760200f;

    unsigned char *p;

    int i;

    p = (char *)&d;

    printf("%f:", d);

    for (i = 0; i < sizeof(d); i++) {

        printf("%02x ", p[i]);

    }

    printf("\n");

    return (0);

}

3 测试结果

要在x86平台上运行,只需像下面这样编译并运行即可:

[root@cyc test]# gcc -o test_double test_double.c

[root@cyc test]# ./test_double

6244.760254:00 00 00 a0 c2 64 b8 40

而要在Sitsang评估板上运行测试程序,只需像下面这样编译程序:

[root@cyc test]# arm-linux-gcc -o test_double test_double.c

然后,再通过NFS或者FTP等途径将编译后的可执行程序test_double下载到Sitsang评估板上,如下执行之[1]:

[root@Sitsang2 TinyGIS]$chmod +x test_double

[root@Sitsang2 TinyGIS]$./test_double

6244.760254:c2 64 b8 40 00 00 00 a0

为了便于对比,不妨以表格的形式将这两种平台的表示方式列出来,如表 1所示。

1 x86和XScale对浮点数表示的对比

double

6244.760200f

X86(PC)

00 00 00 a0               c2 64 b8 40

XScale(Sitsang)

c2 64 b8 40               00 00 00 a0

从表 1可知:浮点数在两种平台上的表示方式的确存在差异,因此,为了能够在Sistang评估板上正确读出数据文件中的浮点数值,应该在读出之后将浮点数的前4字节与后4字节交换。

4 对策

用一个宏即可解决浮点数表示不同的问题。以下就是作者所编写的宏,可能效率不是太高,但是比较容易理解,姑且采用之。

// for double float on PXA255, I found that its

// first 4 bytes and second 4 bytes should swaped

// to act as it does in X86 PC platform, so I define

// this macro, when work on X86 PC, this macro

// is defined as empty

#if defined(PXA_XSCALE)

    #define SWAP_DOUBLE(x)                           \

                do {                                                    \

                    unsigned int *p, t;                            \

                    p = (unsigned int *)&x;                    \

                    t = p[0];                                          \

                    p[0] = p[1];                                     \

                    p[1] = t;                                          \

                }while(0)

#elif defined(X86_PC)

    #define SWAP_DOUBLE(x)

#endif

宏定义SWAP_DOUBLE()是程序中真正需要的,对于PC平台,不需要交换浮点数的前后4个字节,因此将SWAP_DOUBLE()定义为空。

测试表明,经过这样的处理之后,得到的结果就是正确的了。

5 猜想

尽管问题已经被解决了,但是其根源作者并未搞清楚。目前的猜测是这样的:由于在很多ARM之类的嵌入式平台上是没有浮点硬件的,因此,对浮点数的处理必须由编译器来完成。而上述浮点表示方式的差异应该是编译器引入的。但这仅仅属于猜想,真实的情况是否如此,尚未找到有力的证据支持。


[1] 输入的值是6244.760200f,但打印出的值是6244.760254f,最后两位的误差是由于计算机的浮点表示精度有限而导致的

排行榜 更多 +
欢乐钓鱼佬

欢乐钓鱼佬

休闲益智 下载
执业护士一点通

执业护士一点通

学习教育 下载
超凡先锋网易正版手游

超凡先锋网易正版手游

飞行射击 下载