提问人:dangling_refrenz 提问时间:9/1/2014 最后编辑:dangling_refrenz 更新时间:3/9/2015 访问量:787
使用 String.format 将浮点值格式化为字符串的 Wierd 结果
Wierd result in formatting float value to string using String.format
问:
我是 Java 的新手。 我大致了解浮点精度和转换的问题,但不确定为什么在 Java 中看到如此荒谬的结果...... 我做到了......
String str1 = String.format("%.02f", 0.001921921f);
String str2 = String.format("%.02f", 9.0921921f);
String str3 = String.format("%.02f", 91.21921f);
String str4 = String.format("%.02f", 911212.09f); // WIERD: Prints 911212.06 !!!
String str5 = String.format("%.02f", 1212f);
并在调试模式下的字符串中看到了这些值(Eclipse 调试器 / Eclipse Platform 4.2.1 / Java SE 6(Mac Mavericks OSX 默认))......
str1 = "0.00"
str2 = "9.09"
str3 = "91.22"
str4 = "911212.06" ===> What the heck ?? Should be "911212.09" or some rounding of that?
str5 = "1212.00"
我完全不明白这一点。
Lemme 还解释了我最终想做什么......
我有一堆输入浮点值,其十进制精度各不相同,由“9.34”、“99.131”等字符串转换而来。
我想截断所有超过秒的小数位,并获得一个包含所有数字的 INT(没有小数位,没有下限/天花板/四舍五入等),即。19.2341 将成为 1923,19.2359 也将是 1923 年而不是 1924 年。
现在我试着做这样的事情
int ival = (int)(float_val * 100.0);
但这存在精度/准确性问题。例如。如果float_val包含 17.3F,则 IVAL 变为 1729。
我认为使用格式化字符串可能会有所帮助,但这也可以进行四舍五入,在尝试时,我还看到了上面的奇怪情况。
知道我做错了什么吗?
现在,对于我的情况,我将只操作原始字符串值来截断小数位并删除小数点,然后转换为 int。
答:
A 具有 23 位精度。要表示 911212.09,在 + 或 - 0.005 的范围内,需要 27 位(我可能偏离 1)。因此,结果关闭也就不足为奇了。float
如果使用(通过从数字文本中删除 ),您将获得 52 位的精度,因此误差将足够小,以至于当您格式化为小数点后两位时,它不会影响结果。double
f
但是使用更好。BigDecimal
顺便说一句,这不是 Java 或 JDK 问题。它将出现在您尝试使用 32 位 IEEE 754 浮点类型的任何语言中。请阅读每个计算机科学家都应该了解的浮点运算知识。
您的问题只是 intern 表示(如 IEEE 754 格式中所述)不够精确,无法按预期进行处理。float
911212.09f
它实际上只存储在一个 32 位的值上,分布如下:
- 符号的 1 位
- 指数为 8 位,并且只有...
- 尾数为 23 位。
这给我们留下了 23 位的精度,而我们可以表示的最接近的 to 实际上是 。float
911212.09
911212.0625
您可以通过阅读此维基百科条目或使用此在线转换器来更深入地了解这一切是如何工作的: IEEE 754 转换器
正如@ajb在他的回答中提到的,只需使用类型就可以让你对这种情况进行排序;)double
即:
// removed 'f' here
// v
System.out.println(String.format("%.02f", 911212.09));
...将输出:
911212.09
评论