gcc 在math.h中使用宏定义(例如M_PI)作为浮点数而非双精度数

yhuiod9q  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(194)

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

ee7vknir

ee7vknir1#

C数字(C20起)

正如Bob在下面提到的,由于C++20,我们有std::numbers。这将导致:

#include <numbers>

    ...
    double PI = std::number::pi;
    float PIF = std::number::pi_v<float>;
    ...

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

提升数字

Alan Stroke的评论中有一个boost constants的链接,我认为它给出了最佳答案。用途:

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

    ...
    boost::math::float_constants::pi
    ...

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

...
    boost::math::double_constants::pi
    ...
    boost::math::long_double_constants::pi
    ...

在内部,Boost使用一个宏,它执行以下等效操作:

M_PI ## F

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

宏(不推荐)

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

#define M_PIF 3.141592653589793238462643383279502884e+00F
  • 请注意数字末尾的F。*

这基本上就是boost在内部所做的事情。这可能实际上是最适合您的情况的解决方案,因为您说您使用的一些编译器根本不支持double(因此,仅仅使用M_PI可能已经是一个开始的问题,并且boost库声明了所有三种类型:floatdoublelong double)中的一个或多个。
如果编译器抱怨常值的数字太多,可以视需要降低值的精确度。

演员阵容

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

...
    static_cast<float>(M_PI)
    ...

这样一个简单的类型转换将阻止编译器将您的数字转换为double,然后再转换回float,这在大多数情况下会使运行速度更快。
请注意,对于某些数字,强制转换可能不会产生与使用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;
}

而输出:

$ g++ -std=c++17 pi.cpp
$ ./a.out
pi1: 3.14159
pi2: 3.14159
pi1 == pi2? true

好吧,至少在英特尔处理器上。无论如何,两者的区别应该是一位,这在大多数情况下可能不是一个问题。

相关问题