在math.h中使用宏定义(例如M_PI),因为float不加倍

dgr*_*rat 5 c++ gcc

我注意到所有数学常数都声明为double,这在某些不存在双精度单位的平台上导致转换问题。GCC标准库中是否有一个开关可以自动向下转换或使用单独的定义?

Ale*_*lke 2

C++ 数字 (C++20 起)

正如下面 Bob 提到的,从 C++20 开始,我们有了std::numbers。这将导致:

#include <numbers>

    ...
    double PI = std::number::pi;
    float PIF = std::number::pi_v<float>;
    ...
Run Code Online (Sandbox Code Playgroud)

尽管 Boost 数字预定义了更多数字,但随着时间的推移,这可能会是前进的方式。


增加数字

艾伦·斯特罗克(Alan Stroke)的评论有一个提升常量的链接,我认为它给出了最好的答案。使用:

#include <boost/math/constants/constants.hpp>

    ...
    boost::math::float_constants::pi
    ...
Run Code Online (Sandbox Code Playgroud)

同样,您可以使用doublelong double常量:

    ...
    boost::math::double_constants::pi
    ...
    boost::math::long_double_constants::pi
    ...
Run Code Online (Sandbox Code Playgroud)

在内部,Boost 使用一个宏,其作用相当于:

M_PI ## F
Run Code Online (Sandbox Code Playgroud)

换句话说,它告诉编译器将该浮点文字读取为 afloat而不是 a double


宏(不推荐)

如果您更喜欢使用类似 C 的常量,您也可以这样声明:

#define M_PIF 3.141592653589793238462643383279502884e+00F
Run Code Online (Sandbox Code Playgroud)

请注意F数字末尾的 。

这几乎就是 boost 内部所做的事情。这实际上可能是您情况下的最佳解决方案,因为您说您使用的某些编译器根本不支持 double (因此仅使用M_PI可能已经是一个问题,并且 boost 库声明了所有三种类型:float, double,和long double)。

如有必要,可以降低值的精度,以防编译器抱怨文字包含太多数字。


投掷

您也可以简单地转换默认值,但是,编译器仍然需要在某种程度上正确支持 double:

    ...
    static_cast<float>(M_PI)
    ...
Run Code Online (Sandbox Code Playgroud)

这样一个简单的转换将阻止编译器将数字转换为双精度,然后再转换回浮点,这在大多数情况下会使运行速度更快。

请注意,对于某些数字,强制转换可能不会产生与使用F后缀相同的值。然而,对于M_PI,它恰好工作得很好:

// create pi.cpp
#include <iostream>
int main(int argc, char * argv[])
{
    float pi1 = 3.14159265358979323846;
    float pi2 = 3.14159265358979323846f;

    std::cout << "pi1: " << pi1 << "\n";
    std::cout << "pi2: " << pi2 << "\n";
    std::cout << "pi1 == pi2? " << std::boolalpha << (pi1 == pi2) << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

和输出:

$ g++ -std=c++17 pi.cpp
$ ./a.out
pi1: 3.14159
pi2: 3.14159
pi1 == pi2? true
Run Code Online (Sandbox Code Playgroud)

好吧,至少在英特尔处理器上是这样。无论如何,差异应该是一点点,这在大多数情况下可能不是问题。