114

我有一个原始浮点数,我需要一个原始双精度数。简单地将浮点数转换为 double 会给我带来奇怪的额外精度。例如:

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

但是,如果不是强制转换,而是将浮点数输出为字符串,并将字符串解析为双精度字符串,我会得到我想要的:

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

有没有比去字符串和返回更好的方法?

4

10 回答 10

134

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

例如(这些数字不正确,我只是在编造)假设你有:

float f = 0.1F;
double d = f;

那么 的值f可能正好是 0.100000234523。d将具有完全相同的值,但是当您将其转换为字符串时,它将“相信”它的精度更高,因此不会尽早四舍五入,并且您会看到已经存在的“额外数字”在那里,但对你隐藏。

当您转换为字符串并返回时,您最终会得到一个双精度值,它比原始浮点数更接近字符串值 - 但只有您真的相信字符串值是您真正想要的值时,这才是好的。

您确定 float/double 是在此处使用的合适类型,而不是BigDecimal?如果您尝试使用具有精确十进制值的数字(例如货币),那么BigDecimalIMO 是更合适的类型。

于 2009-05-27T14:42:39.413 回答
46

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

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 将浮点数扩展为双精度,但 0.27 的双精度表示“更准确”,因此存在问题。

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000
于 2012-02-07T08:45:44.683 回答
25

这是由于 的合同Float.toString(float)其中部分内容是:

小数部分 […] 必须打印多少位?必须至少有一个数字来表示小数部分,除此之外,必须有尽可能多的数字,但仅能 将参数值与浮点类型的相邻值区分开来。也就是说,假设 x 是由该方法为有限非零参数 f 生成的十进制表示所表示的精确数学值。那么 f 必须是最接近 x 的浮点值;或者,如果两个浮点值同样接近 x,则 f 必须是其中之一,并且 f 的有效位的最低有效位必须为 0。

于 2009-05-27T14:56:04.347 回答
16

我今天遇到了这个问题,无法使用重构到 BigDecimal,因为该项目非常庞大。但是我找到了解决方案

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

这有效。

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

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

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

于 2013-01-02T12:24:55.653 回答
10

我找到了以下解决方案:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

如果您使用floatdouble而不是FloatDouble ,请使用以下内容:

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}
于 2017-01-25T16:20:59.060 回答
7

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

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

于 2009-05-27T14:45:28.750 回答
1

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

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

于 2009-05-27T14:55:36.220 回答
0

有关信息,请参阅 Joshua Bloch 的 Effective Java 2nd edition 的第 48 条 - 当需要精确值时避免使用浮点数和双精度数。这本书塞满了好东西,绝对值得一看。

于 2009-05-27T15:05:43.033 回答
0

这行得通吗?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;
于 2016-03-04T12:18:15.543 回答
0

一个行之有效的简单解决方案是从浮点数的字符串表示中解析双精度:

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

效率不高,但很有效!

于 2020-05-21T14:55:04.453 回答