我有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
在Windows上,我得到了正确的结果(或者似乎是这样,因为最终结果还可以)。
在Linux上,我在Windows中获得了NaN
或一些非常小的数字。
我错过了什么?
编辑#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投影方程的一部分。
答案 0 :(得分:4)
首先,没有理由期待相同的结果, 除非您采取积极措施以确保具体结果。该 C ++语言定义允许使用中间结果 扩展精度。通常,如果编译器执行此操作(和 在英特尔架构上这样做很常见 扩展精度将被截断为标准双精度 编译器存储到内存时的精度。当它 存储到内存将取决于编译器的内部 (甚至可能在优化程度上)。
在英特尔的情况下,现代芯片包含多个浮动 点处理器:旧的FPU使用扩展精度,其中 因为较新的SSE变体没有。但较新的SSE变种 在较旧的处理器上不可用。默认情况下,g ++( Linux编译器)使用旧的FPU,无处不在,但是 据我所知,Visual C ++使用SSE。这意味着 默认情况下,您将获得不同的结果。两个编译器都有 改变这个的广泛选择,但如果你正在运行 默认配置,我不期望g ++和Visual 给出相同的结果。
答案 1 :(得分:1)
我得到nan
的{{1}}值介于90和270之间。这似乎是合理的,因为在该范围内,lat
将返回一个负数,后来不能简单地将其提升为小数权力cot()
。
问题仍然是为什么你在Windows上得到不同的结果。但除非你提供有关具体输入值的信息,否则我不能多说。