抱歉,这个例子是 C 而不是 C++。适应应该不难:
~ $ gcc -mfpmath=387 -mno-sse2 c.c
~ $ ./a.out
incredible but true.
~ $ gcc -mfpmath=sse -msse2 c.c
~ $ ./a.out
~ $ cat c.c
#include "stdio.h"
double d = 3. / 7.;
double d1 = 3.;
int main() {
if (d != d1 / 7.)
printf("incredible but true.\n");
return 0;
}
gcc -msse2 -mfpmath=sse
是一个严格的 IEEE 754 编译器。使用该编译器,if
永远不会采用。但是,gcc -mno-sse2 -mfpmath=387
必须使用精度更高的387单元。它不会降低!=
测试前的精度。测试最终将右侧的 3. / 7. 的扩展精度结果与左侧相同除法的双精度结果进行比较。这会导致可能看起来很奇怪的行为。
两者gcc -msse2 -mfpmath=sse
都gcc -mno-sse2 -mfpmath=387
符合标准。只是前者很容易,生成 SSE2 指令,因此可以提供严格的 IEEE 754 实现,而后者必须尽力使用古老的指令集。
一个循环,例如:
while (eps1 != 1.0f)
eps /= 2.0f, eps1 = 1.0f + eps;
witheps1
声明的类型float
在扩展精度方面应该更加健壮。
生成在比较之前不截断的 x87 代码的编译器是这个:
~ $ gcc -v
Using built-in specs.
Target: i686-apple-darwin11
Configured with: /private/var/tmp/llvmgcc42/llvmgcc42-2336.11~148/src/configure --disable-checking --enable-werror --prefix=/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2 --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-prefix=llvm- --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin11 --enable-llvm=/private/var/tmp/llvmgcc42/llvmgcc42-2336.11~148/dst-llvmCore/Developer/usr/local --program-prefix=i686-apple-darwin11- --host=x86_64-apple-darwin11 --target=i686-apple-darwin11 --with-gxx-include-dir=/usr/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
这是另一个:
~ $ clang -mno-sse2 c.c
~ $ ./a.out
incredible but true.
~ $ clang -v
Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix