<ctgmath> 标头似乎不起作用?

问题描述 投票:0回答:1

我正在编写一些数值模拟代码,因此我非常清楚我使用的浮点类型,并且经常在

float
double
long double
之间切换。我发现 tgmath.h 应该通过提供有用的宏来解决这个问题,但我无法让它工作!在以下代码中,
sqrt(10.0f)
返回完整的双精度平方根,而
sqrtf
的行为符合预期。

#include <tgmath.h>
#include <iostream>
#include <iomanip>

int main(){
    std::cout<<std::setprecision(16);
    std::cout<<sqrt(10.0f)<<std::endl;
    std::cout<<sqrtf(10.0f)<<std::endl;
    return 0;
}

我希望这会输出相同的数字两次,因为

sqrt(float)
应该通过 tgmath 的功能计算为
sqrtf(float)
。相反,它输出双浮点精度值,然后输出单精度值。

3.16227766016838 
3.162277698516846

我使用的是 Ubuntu,我使用命令

g++ floattest.cpp -std=c++11 -o floattest
进行编译。较高版本的 C++ 行为相同,较低版本
-std=c++03
-std=c++98
都无法使用
error: ‘__builtin_tgmath’ was not declared in this scope
进行编译。编译错误确实显示
In file included from /usr/include/c++/11/tgmath.h

是的,我完全忽略了 tgmath.h 的标头吗?我将如何运行依赖于 tgmath.h 的旧 C++ 代码?对于我当前的项目,我可以定义自己的 C++11 _Generics,但很高兴知道发生了什么。

Ubuntu版本:22.04 g++版本:g++(Ubuntu 11.4.0-1ubuntu1~22.04)11.4.0

c++ floating-point tgmath
1个回答
0
投票
C++ 中的

<tgmath.h>
定义为 (by [tgmath.h.syn]):

#include <cmath>
#include <complex>

...这并不能保证定义了名为

::sqrt
的函数。

在 glibc 中,这些签名是暴露的:

// (In the global :: namespace, defined by including <math.h>)
float sqrtf(float);
double sqrt(double);
long double sqrtl(long double);

// (Added for C++ <cmath>)
namespace std {
    float sqrtf(float);
    long double sqrtl(long double);

    float sqrt(float);
    double sqrt(double);
    long double sqrt(long double);
}

因此

sqrt(10.0f)
只能找到
::sqrt(double)
,将其转换为双精度。

要在选择正确函数的宏中获得

_Generic
的 C 行为,请使用重载的
std::sqrt

对旧的(且不正确的)C++ 代码的快速修复是全局命名空间中的

using std::sqrt;
,但从长远来看,最好只移植
sqrt
->
std::sqrt

© www.soinside.com 2019 - 2024. All rights reserved.