高精度双打的sprintf格式问题 我最近升级了一个使用Visual Studio 2012——WindowsXP(V1xXP)平台工具集构建的旧C++项目。在这个项目的代码中,有一些非常精确的双重计算需要多达20个字符的精度。然后将这些双精度数据保存为字符串,并使用printfapi打印出来。以下是本项目中可能发生的情况的示例: double testVal = 123.456789; // do some calculations on testVal char str[100] = { 0 }; sprintf(str, "%.20le", testVal);

高精度双打的sprintf格式问题 我最近升级了一个使用Visual Studio 2012——WindowsXP(V1xXP)平台工具集构建的旧C++项目。在这个项目的代码中,有一些非常精确的双重计算需要多达20个字符的精度。然后将这些双精度数据保存为字符串,并使用printfapi打印出来。以下是本项目中可能发生的情况的示例: double testVal = 123.456789; // do some calculations on testVal char str[100] = { 0 }; sprintf(str, "%.20le", testVal);,c++,visual-studio-2012,printf,c++17,visual-studio-2019,C++,Visual Studio 2012,Printf,C++17,Visual Studio 2019,执行此操作后,str=“1.23456789000…000e+02”,这是预期的结果 但是,一旦我更新项目与VisualStudio 2019兼容,使用Visual Studio 2019(V142)平台工具集,用C++ 17,上述代码产生不同的STR输出。 调用sprintf将值格式化为字符串后,str=“1.23456789000…556e+02”。这个问题并不是局限于这一个值,还有更多的问题。例如,在sprintf格式更改为“2.2343333243219995499e+07”之后,“22

执行此操作后,str=“1.23456789000…000e+02”,这是预期的结果

但是,一旦我更新项目与VisualStudio 2019兼容,使用Visual Studio 2019(V142)平台工具集,用C++ 17,上述代码产生不同的STR输出。 调用

sprintf
将值格式化为字符串后,
str=“1.23456789000…556e+02”
。这个问题并不是局限于这一个值,还有更多的问题。例如,在
sprintf
格式更改为
“2.2343333243219995499e+07”之后,
“2234332.434322”
的一个起始值

从我阅读的所有关于“l”格式代码的文档中,它应该是将长双精度转换为字符串的正确字符。这种行为感觉就像教科书上的浮动->双重转换

我尝试将projects浮点模型build参数设置为precise、strict,然后设置为fast,以查看这些选项是否有帮助,但对问题没有影响

有人知道为什么会发生这种情况吗?

使用全新的Ryu()或Grisu-Exact(),它们比
sprintf
快得多,并且保证往返正确(甚至更多),或者使用旧的双转换(),它比其他两个慢,但保证相同,仍然比
sprintf
快得多,而且是经过战斗考验的

(免责声明:我是Grisu Exact的作者。)

我不确定你是否真的需要准确地打印出20位小数,因为我个人很少有需要数字的情况。如果拥有20位的唯一目的只是为了不丢失任何精度,那么上述库肯定会为您提供更好(更短)的结果。如果由于某些原因,位数必须精确到20,那么Ryu仍然提供这样一个功能(称为Ryu printf),它同样具有往返保证,并且比sprintf快得多

编辑

为了更详细地阐述最后一句话,请注意,一般来说,如果位数是固定的,就不可能有往返保证,因为如果固定的位数太小,比如说3,那么就无法区分0.123和0.1234。但是,20足够大,因此真实值的最佳近似值(Ryu printf生成的值)始终保证是往返正确的。

使用全新的Ryu()或Grisu-Exact(),它们比
sprintf
快得多,并且保证是往返正确的(以及更多),或者使用良好的旧双转换()它比另外两个慢,但有相同的保证,仍然比sprintf快得多,并且经过了战斗测试

(免责声明:我是Grisu Exact的作者。)

我不确定你是否真的需要准确地打印出20位小数,因为我个人很少有需要数字的情况。如果拥有20位的唯一目的只是为了不丢失任何精度,那么上述库肯定会为您提供更好(更短)的结果。如果由于某些原因,位数必须精确到20,那么Ryu仍然提供这样一个功能(称为Ryu printf),它同样具有往返保证,并且比sprintf快得多

编辑


为了更详细地阐述最后一句话,请注意,一般来说,如果位数是固定的,就不可能有往返保证,因为如果固定的位数太小,比如说3,那么就无法区分0.123和0.1234。但是,20足够大,因此真实值的最佳近似值(Ryu printf生成的值)始终保证是往返正确的。

您是否关心发生更改的原因,或者您是否认为新结果不正确?正确地说,IIRC双精度精度只有约17位小数,因此,结尾处的3个“垃圾”数字是意料之中的。我认为新的结果是不正确的。不同的值会导致应用程序中出现一些问题。您可能需要阅读以下链接:。此外,还不能保证转换为字符串的浮点或双精度浮点将以零错误(尤其是不跨平台或编译器)正确返回浮点。@john较新的visualstudio实际上给出了更准确的值
123.456789
四舍五入到最近时实际上是
123.4567890000555701262783259153366088671875
。不幸的是,x64(以及Visual Studio)没有提供更大的浮点类型。您是否关心为什么会发生更改,或者您是否认为新的结果不正确?IIRC正确地说,双精度只有大约17位小数,因此,结尾处的3个“垃圾”数字是意料之中的。我认为新的结果是不正确的。不同的值会导致应用程序中出现一些问题。您可能需要阅读以下链接:。此外,还不能保证转换为字符串的浮点或双精度浮点将以零错误(尤其是不跨平台或编译器)正确返回浮点。@john较新的visualstudio实际上给出了更准确的值
123.456789
四舍五入到最近时实际上是
123.4567890000555701262783259153366088671875
。不幸的