我正在阅读计算机系统:程序员的观点这本书,我正在尝试使用英特尔酷睿i7执行我在Macbook Pro上提供的代码。
但是有些代码并没有完全按照本书的建议运行。
这个C示例应该证明当存储在寄存器中时,存储在存储器中的相同浮点数会有所不同。
#include<stdio.h>
double recip( int denom )
{
return 1.0/(double) denom;
}
void do_nothing(){} /* to clear the register */
void fcomp( int denom)
{
double r1, r2;
int t1, t2;
r1 = recip(denom); /* stored in memory */
r2 = recip(denom); /* stored in register */
t1 = r1 == r2; /* Compares register to memory */
do_nothing(); /* Forces register save to memory */
t2 = r1 == r2; /* Compares memory to memory */
printf("test1 t1: r1 %f %c= r2 %f\n", r1, t1 ? '=' : '!', r2);
printf("test1 t1: r2 %f %c= r2 %f\n", r1, t2 ? '=' : '!', r2);
}
main(){
int demon = 10;
fcomp(demon);
}
与带有“O2”选项的gcc相比,本书建议的结果应为:
test1 t1: r1 0.100000 != r2 0.100000
test2 t1: r1 0.100000 == r2 0.100000
然而,我得到两个“==”并且想知道为什么。有关本书环境设置的任何建议吗?非常感谢。
答案 0 :(得分:1)
本书中的示例(最有可能)针对Intel CPU中x87 FPU的特定属性:此FPU类型的主要特性是它仅提供具有(可见)80位精度的寄存器。因此,当加载到FPU寄存器中时,32或64位浮点数将转换为80位浮点数。此外,通常以完全精度执行算术运算,因此如果将值保存在FPU寄存器中以供以后使用,则不会舍入到32位或64位,因为它是对复制到存储器然后加载的值所做的以后回来。因此,如果将值保存在寄存器中,则会产生差异。
但是,Mac OS X(我认为你在Macbook上使用)没有使用x87 FPU,它使用SSE单元:SSE提供32位和64位浮点寄存器和操作,所以没有区别如果一个值保存在寄存器中或存储在内存中有关其精度的话。每次操作后,结果总是四舍五入。这通常适用于Windows和Linux上的64位exectubles。
例如32位,Linux或Windows的情况有所不同。 x87或SSE单元的使用取决于环境,通常使用x87 FPU,因为32位机器可能不支持所需的SSE2指令,尽管最后一个没有SSE2的CPU是在大约10年前制造的。
答案 1 :(得分:0)
答案不多,但我对此进行了一些研究。我找到了这个fcomp.c http://csapp.cs.cmu.edu/public/1e/ics/code/data/fcomp.c,看起来它可能来自你书中的同一个例子,但你的版本只包含第一个测试。无论如何,我玩各种不同的gcc版本和-m32 vs -m64,发现test1(与你的测试相同)总是相等,至少对于i386和x86_64。
然而,有一个测试(test2)似乎表现出与架构相关的行为:
void test2(int denom)
{
double r1;
int t1;
r1 = recip(denom); /* Default: register, Forced store: memory */
t1 = r1 == 1.0/(double) denom; /* Compares register or memory to register */
printf("test2 t1: r1 %f %c= 1.0/10.0\n", r1, t1 ? '=' : '!');
printf("A long double on this machine requires %d bytes\n", sizeof(long double));
}
(以2的恶魔调用test2())
使用gcc -m64 -o fcomp fcomp.c
进行编译时,我得到了这个输出:
test2 t1: r1 0.100000 == 1.0/10.0
A long double on this machine requires 16 bytes
当使用gcc -m32 -o fcomp fcomp.c
进行编译时,我得到了这个输出:
test2 t1: r1 0.100000 != 1.0/10.0
A long double on this machine requires 12 bytes
为了记录,我使用gcc 3.4.6和4.1.2获得了这些结果。
无论我使用什么编译器/拱门,所有其他测试都是相同的。