如何在 Qt 中打印所有小数点的双精度值?
How to print double with all decimals in Qt?
首先,这不是重复的。我在网上搜索过,但没有足够的答案。
我想打印一个双。所以我必须将它转换为 QString。我想要没有科学计数法,0.1 应该打印 0.1 和 1/3 应该打印尽可能多的 0.33333 ... double 能够表示。不幸的是,我只能找到具有固定精度的解决方案,这会导致上限为 0.333333(在指定的 p 松动精度后结束)或不必要的零填充 0.100000.
我知道我可以最大化精度并删除所有尾随零,但是有没有一个很好的解决方案,它只打印最大可能但最小必要精度?
编辑: 我想我需要澄清一些事情。这道题不是要将实数的 space 映射为单精度、双精度或任何精度的浮点数。它是关于逆向的:将 64 位双精度浮点数 space 映射到我们心爱的现实世界中的实数。由于前者是后者的子集,因此理论上这样做绝对没有问题。
尝试最简单的方法 QString::number(1.0/3.0, 'g', 17);
或者当使用 std::ostream
时 std::setprecision 用于控制 operator<<
的小数位数
问题
与这里的其他评论和答案相反,这是一个非常合理的要求,而且问题看起来很清楚。 Floating-point 到字符串的转换通常应该具有问题中描述的属性,而不是 C 和 C++ 标准库中的原始形式。您不需要指定精度,因为算法应该使用必要的精度。扩展一点,假设您选择固定精度 6。然后打印三个没有科学记数法的 64 位浮点数,(最接近的)0.1、1.0/3.0 和 1.0/3000.0:
0.100000
0.333333
0.003333
这里有几个问题。对于 0.1,末尾打印了不必要的零。打印 0.1
更加清晰和准确。对于其他数字,该值已被截断。一个 64 位浮点数可以表示 15 位以上的十进制数字,但我们只是打印了 6。如果将字符串转换回浮点数,将不会得到相同的值。所以让我们选择精度 17:
0.10000000000000001
0.33333333333333331
0.00333333333333333
现在我们更好地表示 1.0/3.0 的值,但 0.1 只是看起来更差。打印 0.1
一样准确并且看起来更好。此外,我们仍在截断 1.0/3000.0。没有固定的精度可供选择以使数字打印得很好。
解决方案
有一个古老且有点慢的算法(Dragon)可以解决这个问题:
http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
还有一个更快的算法 Grisu,于 2010 年发布,但它需要回退到 Dragon 等算法以获得 floating-point 个数的 0.5%:
http://dl.acm.org/citation.cfm?doid=1809028.1806623
多种语言实现采用 Grisu 来打印 floating-point 数字(例如 Firefox 和 Chrome 的 JS 引擎和 Rust 的标准库)。还有一个 2016 年刚刚发布的算法 Errol,它改进了 Grisu,不需要回退到 Dragon。它太新了,可能还没有被采用:
http://dl.acm.org/citation.cfm?id=2837654
我今天需要很好的 floating-point 打印,所以我一直在试验 Qt,但 Qt 似乎无法完成问题所要求的。 QString::number
和 QString::arg
都使用了糟糕的算法。
在Qt 5.7新特性列表中,有这样的注释:
Added the ability to convert a floating point to its shortest, exact string form, without having to pre-calculate how many digits that is; QVariant uses this
在我的测试中,使用QVariant{floatValue}.toString()
似乎可以满足要求,除了非常小和大的数字仍然使用科学计数法。这是 Grisu 算法的发明者的 C++ 库,看起来很棒(它允许选择何时使用科学记数法):
首先,这不是重复的。我在网上搜索过,但没有足够的答案。
我想打印一个双。所以我必须将它转换为 QString。我想要没有科学计数法,0.1 应该打印 0.1 和 1/3 应该打印尽可能多的 0.33333 ... double 能够表示。不幸的是,我只能找到具有固定精度的解决方案,这会导致上限为 0.333333(在指定的 p 松动精度后结束)或不必要的零填充 0.100000.
我知道我可以最大化精度并删除所有尾随零,但是有没有一个很好的解决方案,它只打印最大可能但最小必要精度?
编辑: 我想我需要澄清一些事情。这道题不是要将实数的 space 映射为单精度、双精度或任何精度的浮点数。它是关于逆向的:将 64 位双精度浮点数 space 映射到我们心爱的现实世界中的实数。由于前者是后者的子集,因此理论上这样做绝对没有问题。
尝试最简单的方法 QString::number(1.0/3.0, 'g', 17);
或者当使用 std::ostream
时 std::setprecision 用于控制 operator<<
问题
与这里的其他评论和答案相反,这是一个非常合理的要求,而且问题看起来很清楚。 Floating-point 到字符串的转换通常应该具有问题中描述的属性,而不是 C 和 C++ 标准库中的原始形式。您不需要指定精度,因为算法应该使用必要的精度。扩展一点,假设您选择固定精度 6。然后打印三个没有科学记数法的 64 位浮点数,(最接近的)0.1、1.0/3.0 和 1.0/3000.0:
0.100000
0.333333
0.003333
这里有几个问题。对于 0.1,末尾打印了不必要的零。打印 0.1
更加清晰和准确。对于其他数字,该值已被截断。一个 64 位浮点数可以表示 15 位以上的十进制数字,但我们只是打印了 6。如果将字符串转换回浮点数,将不会得到相同的值。所以让我们选择精度 17:
0.10000000000000001
0.33333333333333331
0.00333333333333333
现在我们更好地表示 1.0/3.0 的值,但 0.1 只是看起来更差。打印 0.1
一样准确并且看起来更好。此外,我们仍在截断 1.0/3000.0。没有固定的精度可供选择以使数字打印得很好。
解决方案
有一个古老且有点慢的算法(Dragon)可以解决这个问题:
http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
还有一个更快的算法 Grisu,于 2010 年发布,但它需要回退到 Dragon 等算法以获得 floating-point 个数的 0.5%:
http://dl.acm.org/citation.cfm?doid=1809028.1806623
多种语言实现采用 Grisu 来打印 floating-point 数字(例如 Firefox 和 Chrome 的 JS 引擎和 Rust 的标准库)。还有一个 2016 年刚刚发布的算法 Errol,它改进了 Grisu,不需要回退到 Dragon。它太新了,可能还没有被采用:
http://dl.acm.org/citation.cfm?id=2837654
我今天需要很好的 floating-point 打印,所以我一直在试验 Qt,但 Qt 似乎无法完成问题所要求的。 QString::number
和 QString::arg
都使用了糟糕的算法。
在Qt 5.7新特性列表中,有这样的注释:
Added the ability to convert a floating point to its shortest, exact string form, without having to pre-calculate how many digits that is; QVariant uses this
在我的测试中,使用QVariant{floatValue}.toString()
似乎可以满足要求,除了非常小和大的数字仍然使用科学计数法。这是 Grisu 算法的发明者的 C++ 库,看起来很棒(它允许选择何时使用科学记数法):