将float转换为double而不会丢失精度

时间:2009-05-27 14:39:16

标签: java floating-point double

我有一个原始浮点数,我需要作为原始双精度数。简单地将浮子铸造成双倍会给我带来奇怪的额外精度。例如:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

但是,如果不是强制转换,我将float作为字符串输出,并将字符串解析为double,我得到我想要的东西:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

有没有比去String更好的方法呢?

11 个答案:

答案 0 :(得分:110)

并不是因为你实际上获得了额外的精确度 - 浮动并没有准确地代表你最初瞄准的数字。双准确表示原始浮点数; toString显示已经存在的“额外”数据。

例如(这些数字不对,我只是在做事)假设你有:

float f = 0.1F;
double d = f;

然后f的值可能正好是0.100000234523。 d将具有完全相同的值,但是当您将其转换为字符串时,它将“信任”它准确到更高的精度,因此不会尽早完成,您将看到“额外的”数字“已经存在,但对你隐藏。

当你转换成一个字符串并返回时,你最终得到一个双倍值,它比原始浮点数更接近字符串值 - 但这只是好的如果你真的相信字符串值是你真正想要的。

你确定float / double是在这里使用的合适类型而不是BigDecimal吗?如果您尝试使用具有精确十进制值的数字(例如金钱),则BigDecimal是更合适的IMO类型。

答案 1 :(得分:33)

我发现转换为二进制表示更容易理解这个问题。

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)));

你可以看到浮点数通过向末尾添加0来扩展为double,但是0.27的双重表示“更准确”,因此问题就出现了。

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

答案 2 :(得分:24)

这是Float.toString(float),的合同,其中部分说明:

  

必须打印多少位数   小部分[...]?那里   必须至少有一位数   代表小数部分,和   除此之外,,但只有那么多,   唯一需要的更多数字   区分参数值   相邻的float类型值。那个   是,假设x是确切的   以数学为代表的数学价值   十进制表示由   这种方法适用于有限非零   论证f。那么f必须是浮点数   最接近x的值;或者,如果两个浮动   值等于x,然后是f   必须是其中之一,而且至少是其中之一   重要的有意义的   f必须为0.

答案 3 :(得分:13)

我今天遇到过这个问题,并且无法对BigDecimal使用重构,因为该项目非常庞大。但是我找到了使用

的解决方案
Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

这很有效。

请注意,调用result.doubleValue()会返回5623.22998046875

但是调用doubleResult.doubleValue()会正确返回5623.23

但我不完全确定它是否是正确的解决方案。

答案 4 :(得分:7)

使用BigDecimal代替float / double。有许多数字不能表示为二进制浮点数(例如,0.1)。因此,您必须始终将结果舍入为已知精度或使用BigDecimal

有关详细信息,请参阅http://en.wikipedia.org/wiki/Floating_point

答案 5 :(得分:5)

我找到了以下解决方案:

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();
}

答案 6 :(得分:1)

漂浮物本质上是不精确的,并且总是有整齐的“问题”。如果精度很重要,那么您可以考虑重构您的应用程序以使用Decimal或BigDecimal。

是的,由于处理器支持,浮点数在计算上比小数快。但是,您想要快速还是准确?

答案 7 :(得分:0)

有关信息,请参阅条款48 - 在需要确切值时避免浮动和加倍,Joshua Bloch的Effective Java 2nd edition。这本书装满了好东西,绝对值得一看。

答案 8 :(得分:0)

这有用吗?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;

答案 9 :(得分:0)

一种有效的简单解决方案是从float的字符串表示形式中解析double:

double val = Double.valueOf(String.valueOf(yourFloat));

效率不是很高,但是可以!

答案 10 :(得分:-1)

如果需要使用包装器:

#
##
####
#######
###########
################
######################