我有 C++ 程序。如果我运行相同部分的代码,Linux 和 Windows 会给出不同的结果。
#include <cmath>
#include <cfloat>
#include <cstdio>
#define MPI 3.141592653589793238462
#define DEG_TO_RAD(x) ((x) * 0.0174532925)
#define cot(x) (1.0 / tan(x))
#define sec(x) (1.0 / cos(x))
double p1 = DEG_TO_RAD(35);
double p2 = DEG_TO_RAD(65);
double lambertN = log(cos(p1) * sec(p2));
lambertN /= (log(tan(0.25 * MPI + 0.5 * p2) * cot(0.25 * MPI + 0.5 * p1)));
double t = tan(0.25 * MPI + 0.5 * p1);
double lambertF = cos(p1) * pow(t, lambertN);
//---------------------------
//specify input coordinates in degrees
double lon = 160.25;
double lat = 245.75;
double longitude = DEG_TO_RAD(lon - 10);
double latitude = DEG_TO_RAD(lat);
double c = cot(0.25 * MPI + 0.5 * latitude);
double lambertPhi = lambertF * pow(c, lambertN);
printf("%f", lambertPhi); // here I got different results on Win and Linux
Run Code Online (Sandbox Code Playgroud)
在 Windows 上,我得到了正确的结果(或者看起来是这样,因为最终结果还可以)。在 Linux 上,我得到了NaN与 Windows 相关的一些非常小的数字。
我错过了什么?
编辑#1:
Windows - Visual Studio 2010 - 通过 GUI 构建
Linux - gcc 版本 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) - 使用 makefile 构建,标志:CFLAGS = -lm -lstdc++ -Wall -O2
两个系统都是64位
PS:如果有人感兴趣,这是Lambert-Conic投影方程的一部分。
首先,没有真正的理由期待相同的结果,除非您采取积极的措施来确保特定的结果。C++ 语言定义允许中间结果使用扩展精度。通常,如果编译器执行此操作(并且在 Intel 架构上执行此操作非常频繁),则当编译器存储到内存时,扩展精度将被截断为标准双精度。它何时存储到内存将取决于编译器的内部结构(甚至可能取决于优化程度)。
就英特尔而言,现代芯片包含多个浮点处理器:较旧的 FPU 使用扩展精度,而较新的 SSE 变体则没有。但是较新的 SSE 变体在较旧的处理器上不可用。默认情况下,g++(Linux 编译器)使用旧的 FPU,可以在任何地方工作,但据我所知,Visual C++ 使用 SSE。这意味着默认情况下,您将获得不同的结果。两种编译器都有大量的选项来改变这一点,但如果你运行的是默认配置,我不希望 g++ 和 Visual 给出相同的结果。