使用 Java Double.toString() 样式格式化更多数字(DecimalFormat 不适用于低精度数字)
核心问题是我需要记录一系列双精度数,每个双精度数具有不同数量的有效数字。这些数字的有效位数差异很大。有些为 0(例如 5257),有些为 2(例如 1308.75),有些则一直到 7(例如 124.1171875)。基本上是小数点后 0 到 7 位有效数字之间的所有内容。
标准 Double.toString() 对于除 7 位有效数字之外的所有内容都表现出色。一直到6位,有效数字全部打印出来,没有任何无效数字。但对于 7 位有效数字,toString() 会对最后一位数字进行四舍五入。即,
5257 -> "5257"
1308.75 -> "1308.75"
124.1171875 -> "124.117188"
我当然尝试使用 DecimalFormat("#.#######"),这解决了丢失有效数字的问题,但它为许多低精度双精度打印了无意义的数字。即,
1308.75 -> "1308.7499998"
这也是不可接受的,因为 1) 它浪费了大量的空间(通常每天记录大于 2 GB 的数据),2) 它扰乱了使用日志的应用程序。
在识别有效数字方面,与 toString() 相比,DecimalFormat 似乎很糟糕,有什么办法可以修复它吗?我只想使用 toString() 风格处理有效数字,并将最大位数从 6 扩展到 7。
有什么想法吗? 谢谢
The central problem is that I have a series of doubles that I need to log, each with varying number of significant digits. The numbers vary greatly in how many significant digits they have. Some have 0 (e.g. 5257), some have 2 (e.g. 1308.75), some have all the way up to 7 (e.g. 124.1171875). Basically everything between 0 to 7 significant digits after the decimal.
Standard Double.toString() works excellent on everything BUT those with 7 significant digits. That is all the way up to 6 digits, the significant digits are all printed without any insignificant digits. But on those with 7 significant digits, toString() rounds off the last digit. I.e.
5257 -> "5257"
1308.75 -> "1308.75"
124.1171875 -> "124.117188"
Of course I tried using DecimalFormat("#.#######"), and that resolved the problem of missing significant digits, but it printed insignificant digits for many of the low precision doubles. I.e.
1308.75 -> "1308.7499998"
This is also unacceptable as 1) it wastes a significant amount of space (typically log >2 GB of data a day) and 2) it messes up the applications using the logs.
DecimalFormat seems to suck compared to toString() when it comes to identifying significant digits, is there anyway to fix it? I just want to use toString() style handling of significant digits, and extend the maximum number of digits from 6 to 7.
Any ideas?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您担心精确保留十进制值,则应该使用 BigDecimal 开头 - double 根本上是不合适的,因为作为二进制浮点类型。
碰巧,我无法在
DecimalFormat
中重现您的 1308.75 行为,这并不令我感到惊讶,因为该值完全可以表示为double.事实上,DecimalFormat 似乎正在应用一些启发式方法,甚至 1308.76 也显示为 1308.76 - 这让我感到惊讶,因为实际值是 1308.759999999999990905052982270717620849609375。这确实意味着,如果您在代码中使用 1308.7599999999999,它将显示为 1308.76,因为就
double
而言,它是完全相同的值。如果您需要区分这两个值,那么您绝对应该使用 BigDecimal。另请注意,1308.75 有 6 位有效数字 - 它有 2 位小数位。值得仔细区分这两个概念。
If you're concerned about preserving decimal values exactly, you should use
BigDecimal
to start with -double
is fundamentally inappropriate, as a binary floating point type.As it happens, I can't reproduce your behaviour of 1308.75 in
DecimalFormat
, which doesn't surprise me because that value is exactly representable as adouble
. In fact,DecimalFormat
appears to be applying some heuristics anyway, as even 1308.76 comes out as 1308.76 - which surprises me as the actual value is 1308.759999999999990905052982270717620849609375. It does mean that if you use 1308.7599999999999 in your code, it will come out as 1308.76, because it's the exact same value as far asdouble
is concerned. If you need to distinguish between those two values, you should definitely be usingBigDecimal
.Also note that 1308.75 has 6 significant digits - it has 2 decimal places. It's worth being careful to differentiate between the two concepts.
我觉得有点奇怪,所以我出去测试了一下。
我尝试了这段代码:
它给了我这个结果:
您可能正在使用“##.######”进行测试(点后仅 6 个 #),或者您的号码可能有尾随数字。要点是##.####### 和##.0000000 格式将四舍五入最后一个小数点(例如,124.11718755 在格式化之前将四舍五入为124.1171876)。如果您希望它被截断,请尝试先截断它,执行如下操作:
It seemed to me a bit strange, that's why I went out and tested.
I tried this code:
And it gave me this result:
You probably were testing with "##.######" (only 6 #s after dot), or your number might have had trailing digits. The point is that ##.####### and ##.0000000 formats will round the last decimal point (e.g. 124.11718755 will be rounded to 124.1171876 before formatting). If you want it to be truncated try to truncate it first, doing something like this:
除了 Jon Skeet 提到的之外,为什么不保留一个 DecimalFormat 数组,每个数组包含多个数字?
Besides what Jon Skeet mentioned, why not keep an array of DecimalFormat, each one fo a number of digits?