2013-10-11 28 views
2

我在看书计算机系统:程序员的视角,我试图执行它在我的MacBook Pro上提供的代码与英特尔酷睿i7 。学习所需的环境设置“*计算机系统:程序员的视角*”

但是有些代码并不完全按照本书的建议运行。

这个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 

不过,我有两个 “==” S,不知为什么。有关该书的环境设置的任何建议?非常感谢。

+0

您应该将本书保存在干燥的桌面上,避免阳光直射... – 2013-10-11 01:37:03

+4

请注意,任何半路体编译器都可以证明对'do_nothing()的调用不起作用,并且不会发出任何代码。顺便说一下,所述编译器还可以可靠地证明'r1'和'r2'应该具有相同的值,并且优化你的赋值,并且优化'printf()'调用中的三元运算符直到'=' '。另外,我没有在代码中看到关于寄存器的任何内容,所以对存储在寄存器中的值进行任何假设都是完全没有根据的。 –

+0

这里有些事情是非常错误的。这本书是由知名人士Randal Bryant撰写的。有些书是在线的。你确定你的代码片段是书中的内容吗?什么是章节,部分和页面? –

回答

1

本书中的示例旨在(很可能)针对Intel CPU中x87 FPU的特定属性:此FPU类型的主要特性是它仅提供具有(可见)80位精度的寄存器。因此,将32或64位浮点数加载到FPU寄存器时,会将其转换为80位浮点数。此外,通常,算术运算是完全精确执行的,所以如果一个值保存在FPU寄存器中供以后使用,则它不会舍入到32或64位,因为这是为了复制到存储器然后加载稍后再回来。由于这个原因,如果一个值保存在一个寄存器中,它会有所不同。但是,Mac OS X(我想你在Macbook上使用的版本)不使用x87 FPU,它使用SSE单元:SSE提供32位和64位浮点寄存器和操作,因此它使得不使用x88 FPU如果一个值保存在一个寄存器中或者存储在内存中有关其精度的差异。每次操作后结果总是四舍五入。这通常适用于Windows和Linux上的64位可执行文件。

在例如32位,Linux或Windows的情况不同。x87或SSE单元的使用取决于环境,通常使用x87 FPU,因为32位机器可能不支持所需的SSE2指令,尽管最后一个没有SSE2的CPU是在大约10年前建立的。

+0

+1这是一个很好的解释,我的经验为我的[非回答]发现的行为(http://stackoverflow.com/questions/19308894/environment-settings-needed-for-learning-computer-systemsa-programmers -pers/19323829#19323829) –

0

没有太多的答案,但我研究了一点点。我发现这个fcomp.c http://csapp.cs.cmu.edu/public/1e/ics/code/data/fcomp.c,看起来它可能来自您的书中的同一个示例,但您的版本仅包含第一个测试。无论如何,我玩过各种不同的海湾合作委员会版本和-m32 vs -m64,发现test1(与您的测试相同)始终相同,至少对于i386和x86_64来说。

然而,有一个测试(测试2),这似乎显示出结构相关的行为:

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()被调用的10恶魔)

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得到了这些结果。

无论我使用什么编译器/拱,所有其他测试都是相同的。

+0

我忘了玩-O选项。无论-O选项如何,所有测试都通过x86_64。但是对于i386,使用-O0 test2失败;用-O1 test4 t1和t2失败并且-O2所有测试都通过。 –