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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/916081/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:01:42  来源:igfitidea点击:

Convert float to double without losing precision

javafloating-pointdouble

提问by Steve Armstrong

I have a primitive float and I need as a primitive double. Simply casting the float to double gives me weird extra precision. For example:

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

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

However, if instead of casting, I output the float as a string, and parse the string as a double, I get what I want:

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

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

Is there a better way than to go to String and back?

有没有比去 String 再回来更好的方法?

采纳答案by Jon Skeet

It's not that you're actuallygetting extra precision - it's that the float didn't accurately represent the number you were aiming for originally. The double isrepresenting the original float accurately; toStringis showing the "extra" data which was already present.

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

For example (and these numbers aren't right, I'm just making things up) suppose you had:

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

float f = 0.1F;
double d = f;

Then the value of fmight be exactly 0.100000234523. dwill have exactly the same value, but when you convert it to a string it will "trust" that it's accurate to a higher precision, so won't round off as early, and you'll see the "extra digits" which were already there, but hidden from you.

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

When you convert to a string and back, you're ending up with a double value which is closer to the string value than the original float was - but that's only good ifyou really believe that the string value is what you really wanted.

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

Are you sure that float/double are the appropriate types to use here instead of BigDecimal? If you're trying to use numbers which have precise decimal values (e.g. money), then BigDecimalis a more appropriate type IMO.

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

回答by Aaron Digulla

Use a BigDecimalinstead of float/double. There are a lot of numbers which can't be represented as binary floating point (for example, 0.1). So you either must always round the result to a known precision or use BigDecimal.

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

See http://en.wikipedia.org/wiki/Floating_pointfor more information.

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

回答by NotMe

Floats, by nature, are imprecise and always have neat rounding "issues". If precision is important then you might consider refactoring your application to use Decimal or BigDecimal.

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

Yes, floats are computationally faster than decimals because of the on processor support. However, do you want fast or accurate?

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

回答by erickson

This is due the contract of Float.toString(float),which says in part:

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

How many digits must be printed for the fractional part […]? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many,more digits as are needed to uniquely distinguish the argument value from adjacent values of type float.That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument f. Then f must be the float value nearest to x; or, if two float values are equally close to x, then f must be one of them and the least significant bit of the significand of f must be 0.

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

回答by mR_fr0g

For information this comes under Item 48 - Avoid float and double when exact values are required, of Effective Java 2nd edition by Joshua Bloch. This book is jam packed with good stuff and definitely worth a look.

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

回答by Brecht Yperman

I find converting to the binary representation easier to grasp this problem.

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

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

You can see the float is expanded to the double by adding 0s to the end, but that the double representation of 0.27 is 'more accurate', hence the problem.

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

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

回答by Andrew

I've encountered this issue today and could not use refactor to BigDecimal, because the project is really huge. However I found solution using

今天遇到了这个问题,不能使用refactor to BigDecimal,因为项目真的很大。但是我找到了解决方案

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

And this works.

这有效。

Note that calling result.doubleValue() returns 5623.22998046875

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

But calling doubleResult.doubleValue() returns correctly 5623.23

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

But I am not entirely sure if its a correct solution.

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

回答by AesmaDiv

Does this work?

这行得通吗?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;

回答by GSD.Aaz

I found the following solution:

我找到了以下解决方案:

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

If you use floatand doubleinstead of Floatand Doubleuse the following:

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

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

回答by Alessandro Roaro

A simple solution that works well, is to parse the double from the string representation of the float:

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

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

Not super efficient, but it works!

不是超级有效,但它有效!