【发布时间】:2020-06-30 15:42:38
【问题描述】:
所以我最近升级了一个使用 Visual Studio 2012 - Windows XP (v110_xp) 平台工具集构建的旧 c++ 项目。在这个项目的代码中,发生了一些非常精确的双重计算,需要多达 20 个字符的精度。然后将这些双打保存到一个字符串中,并使用printf API 打印出来。以下是该项目中将发生的事情的示例:
double testVal = 123.456789;
// do some calculations on testVal
char str[100] = { 0 };
sprintf(str, "%.20le", testVal);
在这个操作之后 str = "1.23456789000...000e+02",这是预期的结果。
但是,一旦我将项目更新为与 Visual Studio 2019 兼容,使用 Visual Studio 2019 (v142) 平台工具集和 c++ 17,上述代码会为 str 生成不同的输出。
在调用sprintf 将值格式化为字符串str = "1.23456789000...556e+02" 之后。这个问题并不局限于这个值,还有更多的问题。例如,sprintf 格式后的"2234332.434322" 的起始值之一更改为"2.23433324343219995499e+07"
从我使用“l”格式代码阅读的所有文档中,它应该是将长双精度转换为字符串的正确字符。这种行为感觉就像教科书的 float->double 转换。
我尝试将项目浮点模型构建参数设置为精确、严格,然后快速查看这些选项中的任何一个是否有帮助,但它对问题没有影响。
有人知道为什么会这样吗?
【问题讨论】:
-
您是担心为什么会发生变化,还是认为新的结果不正确?
-
IIRC 正确地,一个双精度数只有大约 17 位十进制数字,所以最后只有 3 个“垃圾”数字。
-
我认为新的结果是不正确的。不同的值会在应用程序中进一步导致一些问题。
-
您可能想阅读以下链接:Is floating point math broken?,What Every Computer Scientist Should Know About Floating-Point Arithmetic。此外,不能保证转换为字符串的浮点数或双精度数会正确往返返回到零错误的浮点数(尤其是不跨平台或编译器)。
-
@john 较新的 Visual Studio 实际上给出了更准确的值。当四舍五入到最接近的IEEE-754 double 时,
123.456789实际上是123.4567890000000005557012627832591533660888671875。不幸的是,x64(以及 Visual Studio)不提供更大的浮点类型。
标签: c++ visual-studio-2012 printf c++17 visual-studio-2019