在不损失精度的情况下将浮点数转换为双精度

2022-08-31 09:14:10

我有一个原始的浮点,我需要作为一个原始的替身。简单地将浮子投掷到双倍会给我带来奇怪的额外精度。例如:

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

有没有比去String和返回更好的方法?


答案 1

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

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

float f = 0.1F;
double d = f;

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

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

您确定浮动/双精度是在这里使用的合适类型而不是?如果您尝试使用具有精确十进制值的数字(例如货币),那么是更合适的IMO类型。BigDecimalBigDecimal


答案 2

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

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

您可以看到,通过在末尾添加 0s,浮点数扩展到双精度,但 0.27 的双重表示“更准确”,因此存在问题。

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000