gpt4 book ai didi

c++ - 浮点相等测试和超精度 : can this code fail?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:54:56 28 4
gpt4 key购买 nike

讨论开始于my answer to another question .以下代码确定 machine epsilon :

float compute_eps() {
float eps = 1.0f;

while (1.0f + eps != 1.0f)
eps /= 2.0f;

return eps;
}

在评论中建议 1.0f + eps != 1.0f 测试可能会失败,因为 C++ 标准允许使用额外的精度。尽管我知道浮点运算实际上以更高的精度执行(比实际使用的类型指定的精度更高),但我碰巧不同意这个提议。

我怀疑在比较操作期间,例如 ==!=,操作数没有被截断到它们类型的精度。换句话说,1.0f + eps当然可以比float(例如,long double)更高的精度求值,而结果将存储在可容纳long double 的寄存器中。但是,我认为在执行 != 操作之前,左操作数将从 long double 截断为 float,因此代码永远不会失败精确确定 eps(即它永远不会进行比预期更多的迭代)。

我在 C++ 标准中没有找到关于这个特殊情况的任何线索。此外,代码运行良好,我确信在执行期间使用了额外的精度技术,因为我毫不怀疑任何现代桌面实现实际上在计算期间使用了额外的精度。

你怎么看?

最佳答案

抱歉,这个例子是 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. 与左侧相同除法的 double 结果进行比较。这会导致看起来很奇怪的行为。

gcc -msse2 -mfpmath=ssegcc -mno-sse2 -mfpmath=387 都符合标准。只是前者很容易生成 SSE2 指令,因此可以提供严格的 IEEE 754 实现,而后者则必须尽力使用古老的指令集。

一个循环,例如:

while (eps1 != 1.0f)
eps /= 2.0f, eps1 = 1.0f + eps;

声明 float 类型的 eps1 应该在扩展精度方面更加稳健。


生成比较前不截断的 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

关于c++ - 浮点相等测试和超精度 : can this code fail?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16325277/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com