gpt4 book ai didi

c++ - libc hypot函数似乎为 double 类型返回不正确的结果……为什么?

转载 作者:行者123 更新时间:2023-12-03 07:21:02 25 4
gpt4 key购买 nike

#include <tgmath.h>
#include <iostream>
int main(int argc, char** argv) {

#define NUM1 -0.031679909079365576
#define NUM2 -0.11491794452567111

std::cout << "double precision :"<< std::endl;
typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10);
std::cout << std::hypot((double)NUM1, (double)NUM2);
std::cout << " VS sqrt :" << sqrt((double )NUM1*(double )NUM1
+ (double )NUM2*(double )NUM2) << std::endl;

std::cout << "long double precision :"<< std::endl;
typedef std::numeric_limits<long double > ldbl;
std::cout.precision(ldbl::max_digits10);
std::cout << std::hypot((long double)NUM1, (long double)NUM2);
std::cout << " VS sqrt :" << sqrt((long double )NUM1*(long double )NUM1 + (long double )NUM2*(long double )NUM2);
}
在Linux下返回(Ubuntu 18.04 clang或gcc,无论优化如何,glic 2.25):
double :
0.1192046585217293 VS sqrt:0.1192046585217293 2
长 double :
0.119204658521729311251 VS sqrt:0.119204658521721729311251
根据cppreference:
实现通常保证 的精度小于1 ulp (最后一个单位):GNU,BSD,Open64
std::hypot(x,y)等同于std::abs(std::complex(x,y))
POSIX指定仅当两个参数都为非正规且正确的结果也为非正规时才发生下溢(这禁止幼稚的实现)
因此,我假设(假设是朴素的sqrt实现)hypot((double)NUM1,(double)NUM2)应该返回0.11920465852172932。
在Windows上,使用MSVC 64位,就是这种情况。
为什么使用glibc会看到这种差异?如何解决这种矛盾?

最佳答案

  • 0.1192046585217293 2 0x1.e84324de1b576p-4表示( double )
  • 0.1192046585217293 0 0x1.e84324de1b575p-4表示( double )
  • 0.1192046585217293 1 1251是长 double 结果,我们可以假设它对另外几个小数位是正确的。即确切的结果更接近于四舍五入的结果。

  • 这些FP位模式仅在尾数的低位(也就是有效位)上有所不同,而 的确切结果在它们之间因此,它们每个的舍入误差均小于1 ulp,实现了典型实现(包括glibc)的目标。
    与IEEE-754“基本”操作(add / sub / mul / div / sqrt)不同, hypot不需要“正确舍入”。这意味着<= 0.5 ulp错误。对于硬件不直接提供的操作而言,要实现这一目标将慢得多。 (例如,至少使用几个绝对正确的位进行扩展精度计算,因此您可以四舍五入到最接近的两倍,就像硬件用于基本操作一样)
    碰巧在这种情况下,幼稚的计算方法产生了正确的舍入结果,而glibc的 std::hypot的“安全”实现(在加法之前对小数进行平方时必须避免下溢)产生的结果> 0.5但误差小于1 ulp 。

    您没有指定是否在32位模式下使用MSVC。
    大概32位模式将使用x87进行FP数学运算,从而提供了额外的临时精度。尽管某些MSVC版本的CRT代码在每次操作后将x87 FPU的内部精度设置为四舍五入为53位尾数,所以它的行为类似于使用实际 double的SSE2,但指数范围更广。参见 Bruce Dawson's blog post
    因此,我不知道是否有除运气之外的其他原因,MSVC的 std::hypot为此获得了正确的取整结果。
    请注意,MSVC中的 long double与64位 double具有相同的类型; C++实现不会公开x86 / x86-64的80位硬件扩展精度类型。 (64位尾数)。

    关于c++ - libc hypot函数似乎为 double 类型返回不正确的结果……为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65106010/

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