developer tip

정밀도를 잃지 않고 float를 double로 변환

optionbox 2020. 9. 5. 09:45
반응형

정밀도를 잃지 않고 float를 double로 변환


나는 기본 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

그러나 캐스팅 대신 float를 문자열로 출력하고 문자열을 double로 구문 분석하면 원하는 것을 얻습니다.

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

String으로 다시 돌아가는 것보다 더 좋은 방법이 있습니까?


그것은 당신이 있다는 것을 아니다 실제로 여분의 정밀도를 얻기 - 그것은 플로트 정확하게 원래 목표로 한 수를 나타냅니다하지 않았다입니다. double 원래 플로트를 정확하게 나타냅니다. toString이미 존재하는 "추가"데이터를 표시합니다.

예를 들어 (그리고이 숫자는 옳지 않습니다. 저는 단지 구성하는 중입니다) 다음과 같이 가정 해보십시오.

float f = 0.1F;
double d = f;

그러면의 값은 f정확히 0.100000234523이 될 수 있습니다. d정확히 같은 값을 가지지 만 문자열로 변환하면 더 높은 정밀도로 정확하다고 "신뢰"할 수 있으므로 일찍 반올림하지 않고 이미 있던 "추가 자릿수"를 볼 수 있습니다. 거기에 있지만 당신에게 숨겨져 있습니다.

문자열로 변환했다가 다시 되돌릴 때 원래 float보다 문자열 값에 더 가까운 double 값으로 끝나게됩니다.하지만 문자열 값이 실제로 원하는 값이라고 믿는 경우 에만 좋습니다 .

대신 float / double이 여기에서 사용하기에 적합한 유형 BigDecimal입니까? 정확한 10 진수 값 (예 : 돈)을 가진 숫자를 사용하려는 경우 BigDecimal더 적절한 유형의 IMO가 있습니다.


이진 표현으로 변환하면이 문제를 더 쉽게 이해할 수 있습니다.

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을 추가하여 float가 double로 확장되는 것을 볼 수 있지만 0.27의 이중 표현은 '더 정확'하므로 문제가 발생합니다.

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

이 계약으로 인해입니다 Float.toString(float), 일부 말한다 :

소수 부분 […]에 대해 몇 자릿수를 인쇄해야합니까? 소수 부분을 표현하기 위해서는 적어도 하나의 숫자가 있어야하며 , 그 이상의 숫자는 인수 값을 float 유형의 인접 값과 고유하게 구별하는 데 필요한만큼만 더 많이 있어야합니다. 즉, x가 0이 아닌 유한 인수 f에 대해이 방법에 의해 생성 된 십진수 표현으로 표현되는 정확한 수학적 값이라고 가정합니다. 그러면 f는 x에 가장 가까운 부동 소수점 값이어야합니다. 또는 두 개의 float 값이 x에 똑같이 가까우면 f는 그 중 하나 여야하며 f의 최하위 비트는 0이어야합니다.


오늘이 문제가 발생했으며 프로젝트가 정말 거대하기 때문에 BigDecimal에 대한 리팩터링을 사용할 수 없습니다. 그러나 나는

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

그리고 이것은 작동합니다.

result.doubleValue ()를 호출하면 5623.22998046875가 반환됩니다.

그러나 doubleResult.doubleValue ()를 호출하면 5623.23이 올바르게 반환됩니다.

그러나 나는 그것이 올바른 해결책인지 완전히 확신하지 못합니다.


/ BigDecimal대신 사용하십시오 . 이진 부동 소수점으로 표현할 수없는 숫자가 많이 있습니다 (예 :) . 따라서 항상 결과를 알려진 정밀도로 반올림하거나 .floatdouble0.1BigDecimal

자세한 내용은 http://en.wikipedia.org/wiki/Floating_point 를 참조하십시오.


다음 해결책을 찾았습니다.

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

당신이 사용하는 경우 플로트를 하고 두 번 대신 플로트두 번 다음을 사용 :

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

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.

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


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.


Does this work?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;

참고URL : https://stackoverflow.com/questions/916081/convert-float-to-double-without-losing-precision

반응형