将浮点数转换为double而不会丢失精度
我有一个原始的浮动,我需要作为一个原始的双。 简单地将浮点数转换为double值给我奇怪的额外精度。 例如:
float temp = 14009.35F; System.out.println(Float.toString(temp)); // Prints 14009.35 System.out.println(Double.toString((double)temp)); // Prints 14009.349609375
然而,如果不是投射,我输出一个string的浮动,并parsingstring为双,我得到我想要的:
System.out.println(Double.toString(Double.parseDouble(Float.toString(temp)))); // Prints 14009.35
有没有更好的方法比去串和回?
这并不是说你实际上得到了更高的精度 – 这是浮点数不能准确地表示你原来想要的数字。 双精确地表示原始的浮标; toString
显示已经存在的“额外”数据。
例如(这些数字是不对的,我只是在做)支持你有:
float f = 0.1F; double d = f;
那么f
的值可能恰好是0.100000234523。 d
将具有完全相同的值,但是当您将其转换为string时,它会“相信”精确到更高的精度,因此不会太早完成,您将看到“额外数字”已经在那里,但对你隐藏。
当你转换成一个string并返回时,最后会得到一个比原来的float值更接近string值的double值 – 但是如果你真的相信string的值是你真正想要的值,那就是好的。
你确定float / double是适合的types而不是BigDecimal
吗? 如果您要使用具有精确小数值(例如金钱)的数字,那么BigDecimal
是更适合的typesIMO。
我发现转换到二进制表示更容易把握这个问题。
float f = 0.27f; double d2 = (double) f; double d3 = 0.27d; System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f))); System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2))); System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));
你可以看到float被扩展为double,通过在最后加上0,但是0.27的双重表示“更准确”,因此是问题所在。
111110100010100011110101110001 11111111010001010001111010111000100000000000000000000000000000 11111111010001010001111010111000010100011110101110000101001000
这是由于Float.toString(float)
的合同,部分地说:
小数部分必须打印多less位数? 必须至less有一位数字才能表示小数部分,并且除此之外还必须有尽可能多的数字,以便唯一地区分参数值和types为float的相邻值。 也就是说,假设x是由这种方法产生的十进制表示的精确math值,用于有限非零参数f。 那么f必须是最靠近x的浮点值; 或者,如果两个浮点数值都等于x,则f必须是其中的一个,而f的有效数的最低有效位必须为0。
我今天遇到这个问题,不能使用重构到BigDecimal,因为这个项目真的很大。 但是我发现解决scheme使用
Float result = new Float(5623.23) Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()
这工作。
请注意,调用result.doubleValue()返回5623.22998046875
但是调用doubleResult.doubleValue()会正确返回5623.23
但是我不完全确定它是否是一个正确的解决scheme。
使用BigDecimal
而不是float
/ double
。 有很多数字不能表示为二进制浮点数(例如0.1
)。 因此,您必须始终将结果四舍五入到已知的精度或使用BigDecimal
。
有关更多信息,请参见http://en.wikipedia.org/wiki/Floating_point 。
我发现了以下解决scheme:
public static Double getFloatAsDouble(Float fValue) { return Double.valueOf(fValue.toString()); }
如果你使用float和double来代替Float和Double,使用下面的代码:
public static double getFloatAsDouble(float value) { return Double.valueOf(Float.valueOf(value).toString()).doubleValue(); }
这是否工作?
float flt = 145.664454; Double dbl = 0.0; dbl += flt;
浮动本质上是不精确的,总是有整齐的“问题”。 如果精度很重要,那么可以考虑重构应用程序以使用Decimal或BigDecimal。
是的,由于处理器支持,浮点运算速度比小数快。 但是,你想快速还是准确?
有关信息,请参阅第48条 – 在需要精确值时避免float和double,Joshua Bloch撰写的Effective Java第2版。 这本书塞满了好东西,绝对值得一看。