如何使用 gnu gcc 标志 -mpc32、-mpc64 和 -mpc80?
How to use gnu gcc flag -mpc32, -mpc64 and -mpc80?
我从 GNU GCC compiler Manual 获得了这些 GCC 标志。但是当我尝试使用这些标志(-mpc32
、-mpc64
和 -mpc80
)时,我无法观察到这种行为。所以我需要有关如何通过示例代码使用这些标志的帮助。
我试过的示例代码:test.cpp
#include<stdio.h>
#include<iomanip>
#include<math.h>
int main()
{
double weight = 1.0f;
double roiSize = 137.142364501953125f;
double thresholdValue = 5400.0f;
double alpha = weight / (roiSize * thresholdValue * thresholdValue);
std::cout<<std::setprecision(100)<<"alpha = "<<f<<std::endl;
double test = pow(roiSize, 10);
std::cout<<std::setprecision(100)<<"alpha = "<<f<<std::endl;
}
编译选项:
g++ -mpc32 test.cpp
g++ -mpc64 test.cpp
g++ -mpc80 test.cpp
测试不同 x87 精度的最简单方法可能是使用 long double
,它在 x86 目标上是 80 位 x87 类型。 (除了 Windows,其中 long double = double)。
long double
的另一个优点是您根本不需要使用 -m32
进行编译就可以使用 x87。 (-m64
的默认值是 -mfpmath=sse
;double 和 float 数学运算将在 XMM 寄存器中以类型宽度完成,不会扩大到 x87 内部精度。但是 long double
将始终使用 x87,因为SSE/SSE2 不能做 80 位)。 TL:DR:在使用 gcc -mpc32 foo.c
构建的普通 64 位系统上,-mpc32
对 double
变量的数学运算没有任何影响,因为它不会甚至使用传统的 x87 FPU。
顺便说一句,此测试用例还依赖于使用默认 -O0
进行编译,否则会在编译时发生不断传播。 (这不太可能尊重 -mpc32
。)
137.142364501953125f
是一个 float
常量,在用作 double
的初始值设定项之前四舍五入为浮点数。因此,尽管存储为 double
,但您的起始值都四舍五入到最接近的 float
。不过,我假设除法不准确,所以您仍然会四舍五入。
我假设这些选项只是在启动时设置 x87 精度。 MSVC 的 CRT 起始代码显然做了类似的事情,默认设置 64 位精度(53 位尾数,如 double
,不是全精度)。参见 Bruce Dawson 的 Intermediate Floating-Point Precision article; one of a series of FP articles. Index in this one.
您可以查看编译器生成的 asm 以了解它如何进行 FP 数学运算:使用 fld
/ fmul
/ fstp
是 x87 并且会受到 x87 精度的影响在 x87 控制字寄存器中设置。
movsd
/ mulsd
是SSE2,精度由指令设置;没有状态/控制位可以覆盖它。 (只有舍入模式可以在 MXCSR 中更改,以及次正规的处理。)
我从 GNU GCC compiler Manual 获得了这些 GCC 标志。但是当我尝试使用这些标志(-mpc32
、-mpc64
和 -mpc80
)时,我无法观察到这种行为。所以我需要有关如何通过示例代码使用这些标志的帮助。
我试过的示例代码:test.cpp
#include<stdio.h>
#include<iomanip>
#include<math.h>
int main()
{
double weight = 1.0f;
double roiSize = 137.142364501953125f;
double thresholdValue = 5400.0f;
double alpha = weight / (roiSize * thresholdValue * thresholdValue);
std::cout<<std::setprecision(100)<<"alpha = "<<f<<std::endl;
double test = pow(roiSize, 10);
std::cout<<std::setprecision(100)<<"alpha = "<<f<<std::endl;
}
编译选项:
g++ -mpc32 test.cpp
g++ -mpc64 test.cpp
g++ -mpc80 test.cpp
测试不同 x87 精度的最简单方法可能是使用 long double
,它在 x86 目标上是 80 位 x87 类型。 (除了 Windows,其中 long double = double)。
long double
的另一个优点是您根本不需要使用 -m32
进行编译就可以使用 x87。 (-m64
的默认值是 -mfpmath=sse
;double 和 float 数学运算将在 XMM 寄存器中以类型宽度完成,不会扩大到 x87 内部精度。但是 long double
将始终使用 x87,因为SSE/SSE2 不能做 80 位)。 TL:DR:在使用 gcc -mpc32 foo.c
构建的普通 64 位系统上,-mpc32
对 double
变量的数学运算没有任何影响,因为它不会甚至使用传统的 x87 FPU。
顺便说一句,此测试用例还依赖于使用默认 -O0
进行编译,否则会在编译时发生不断传播。 (这不太可能尊重 -mpc32
。)
137.142364501953125f
是一个 float
常量,在用作 double
的初始值设定项之前四舍五入为浮点数。因此,尽管存储为 double
,但您的起始值都四舍五入到最接近的 float
。不过,我假设除法不准确,所以您仍然会四舍五入。
我假设这些选项只是在启动时设置 x87 精度。 MSVC 的 CRT 起始代码显然做了类似的事情,默认设置 64 位精度(53 位尾数,如 double
,不是全精度)。参见 Bruce Dawson 的 Intermediate Floating-Point Precision article; one of a series of FP articles. Index in this one.
您可以查看编译器生成的 asm 以了解它如何进行 FP 数学运算:使用 fld
/ fmul
/ fstp
是 x87 并且会受到 x87 精度的影响在 x87 控制字寄存器中设置。
movsd
/ mulsd
是SSE2,精度由指令设置;没有状态/控制位可以覆盖它。 (只有舍入模式可以在 MXCSR 中更改,以及次正规的处理。)