문제

public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

위의 코드 인쇄 :

11.399999999999

11.4 만 인쇄하거나 사용하도록하려면 어떻게해야합니까?

도움이 되었습니까?

해결책

다른 사람들이 언급했듯이 아마도 BigDecimal 클래스, 정확한 표현이 11.4를 원한다면.

이제 왜 이런 일이 일어나고 있는지에 대한 약간의 설명 :

그만큼 float 그리고 double Java의 원시 유형입니다 부동 소수점 숫자가 분수 및 지수의 이진 표현으로 저장되는 숫자.

보다 구체적으로 double 유형은 64 비트 값입니다.

  • 1 비트는 부호를 나타냅니다 (양수 또는 음수).
  • 지수를위한 11 비트.
  • 유의 한 숫자에 대한 52 비트 (이진으로서의 분수 부품).

이 부분은 a를 생산하기 위해 결합됩니다 double 값의 표현.

(원천: 위키 백과 : 이중 정밀도)

부동 소수점 값이 Java로 처리되는 방법에 대한 자세한 설명은 섹션 4.2.3 : 부동 소수점 유형, 형식 및 값 Java 언어 사양의.

그만큼 byte, char, int, long 유형은 고정점 숫자의 정확한 표현 인 숫자. 고정 점수와 달리 부동 소수점 번호는 때때로 ( "대부분의 시간"을 가정하기에 안전) 숫자의 정확한 표현을 반환 할 수 없습니다. 이것이 당신이 끝나는 이유입니다 11.399999999999 결과로 5.6 + 5.8.

1.5 또는 150.1005와 같이 정확한 값이 필요한 경우 고정점 유형 중 하나를 사용하여 숫자를 정확하게 나타낼 수 있습니다.

이미 여러 번 언급 된 바와 같이, Java는 BigDecimal 매우 많은 숫자와 매우 적은 숫자를 처리하는 클래스.

Java API 참조에서 BigDecimal 수업:

불변의 임의의 자료에 서명 된 소수점 수치. Bigdecimal은 임의의 정밀 정수 값이없는 값과 32 비트 정수 척도로 구성됩니다. 0이거나 양수 인 경우, 스케일은 소수점의 오른쪽에있는 숫자 수입니다. 음수 인 경우, 숫자의 미지급 값은 스케일의 부정의 힘에 10을 곱합니다. 따라서 Bigdecimal으로 표시되는 숫자의 값은 (unscaledValue × 10^-scale)입니다.

플로팅 포인트 수와 정밀도와 관련하여 스택 오버플로에 대한 많은 질문이있었습니다. 다음은 관심있는 관련 질문 목록입니다.

플로팅 포인트 번호의 끔찍한 세부 사항으로 내려 가고 싶다면 살펴보십시오. 모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 것.

다른 팁

예를 들어 이중 번호를 입력하면 33.33333333333333, 당신이 얻는 값은 실제로 가장 가까운 대표 이중 정제 값입니다. 정확히 다음과 같습니다.

33.3333333333333285963817615993320941925048828125

그것을 100으로 나누면 :

0.333333333333333285963817615993320941925048828125

또한 이중 프레시션 번호로 표현할 수 없으므로 다시 한 번 가장 가까운 대표 값으로 반올림됩니다. 정확히 다음과 같습니다.

0.3333333333333332593184650249895639717578887939453125

이 값을 인쇄하면 둥글게됩니다. 다시 한번 17 자리 숫자로 : 제공 :

0.33333333333333326

값을 분수로 처리하려면 분자 및 분모 필드를 보유하는 분수 클래스를 만들 수 있습니다.

추가, 빼기, 곱하기 및 분열 및 토할 방법을 작성하십시오. 이렇게하면 계산 중에 수레를 피할 수 있습니다.

편집 : 빠른 구현,

public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}

제한된 프로 10 소수의 산술을 사용하고 1/3 : 0.333333333 * 3을 처리하려는 경우 1.00000000이 아닌 0.99999999입니다.

불행히도, 5.6, 5.8 및 11.4는 바이너리에서 둥근 숫자가 아닙니다. 5 분의 1이 포함됩니다. 따라서 0.3333이 정확히 1/3이 아님과 마찬가지로 그것의 플로트 표현은 정확하지 않습니다.

사용하는 모든 숫자가 반복되지 않은 소수점이고 정확한 결과를 원한다면 BigDecimal을 사용하십시오. 또는 다른 사람들이 말했듯이, 귀하의 가치가 모두 0.01의 배수 또는 0.001 또는 무언가라는 의미에서 돈과 같다면 모든 것을 고정 된 전력 10으로 곱하고 int 또는 long을 사용합니다 (추가 및 뺄셈은 다음과 같습니다. 사소한 : 곱셈을 조심하십시오).

그러나 계산을 위해 바이너리에 만족하지만 약간 더 친근한 형식으로 물건을 인쇄하고 싶다면 시도하십시오. java.util.Formatter 또는 String.format. 형식으로 문자열은 이중의 전체 정밀도보다 적은 정밀도를 지정합니다. 예를 들어, 11.399999999999는 11.4이므로 이진 결과가 소수점 이하 자리만이 필요한 값에 매우 가까운 경우 결과는 거의 정확하고 인간이 읽을 수 있습니다.

지정해야 할 정밀도는 숫자로 수행 한 수학의 양에 따라 다릅니다. 일반적으로 더 많이할수록 더 많은 오류가 축적되지만 일부 알고리즘은 다른 것보다 훨씬 빠르게 축적됩니다 ( "불안정"이라고합니다. 반올림 오류와 관련하여 "안정적인"것에 반대). 만약 당신이하고있는 모든 것이 몇 가지 값을 추가하는 것만이라면, 단 하나의 십진자가 정밀도를 떨어 뜨리면 물건을 분류 할 것이라고 생각합니다. 실험.

정밀 수학이 필요한 경우 Java 's Java.math.bigdecimal 클래스를 사용하여 살펴볼 수 있습니다. 다음은 Oracle/Sun의 좋은 기사입니다. Bigdecimal의 사례. 누군가가 언급했듯이 1/3을 대표 할 수는 없지만 ~할 수 있다 결과가 얼마나 정확한지 정확하게 결정할 수있는 힘이 있습니다. setScale ()는 당신의 친구입니다 .. :)

좋아, 여기에 내 손에 너무 많은 시간이 있기 때문에 여기에 당신의 질문과 관련된 코드 예제가 있습니다.

import java.math.BigDecimal;
/**
 * Created by a wonderful programmer known as:
 * Vincent Stoessel
 * xaymaca@gmail.com
 * on Mar 17, 2010 at  11:05:16 PM
 */
public class BigUp {

    public static void main(String[] args) {
        BigDecimal first, second, result ;
        first = new BigDecimal("33.33333333333333")  ;
        second = new BigDecimal("100") ;
        result = first.divide(second);
        System.out.println("result is " + result);
       //will print : result is 0.3333333333333333


    }
}

그리고 내가 가장 좋아하는 언어 인 Groovy를 막기 위해 여기에 같은 것의 깔끔한 예가 있습니다.

import java.math.BigDecimal

def  first =   new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")


println "result is " + first/second   // will print: result is 0.33333333333333

당신은 그것을 세 줄 예로 만들 수 있다고 확신합니다. :)

정확한 정밀도를 원한다면 BigDecimal을 사용하십시오. 그렇지 않으면 원하는 정밀도를 10 ^ 곱한 ints를 사용할 수 있습니다.

다른 사람들이 지적했듯이, 소수점은 10의 전력을 기반으로하고 바이너리가 2의 전력을 기반으로하기 때문에 모든 소수점 값을 바이너리로 표현할 수있는 것은 아닙니다.

정밀도가 중요한 경우 BigDecimal을 사용하지만 친근한 출력을 원한다면 :

System.out.printf("%.2f\n", total);

당신에게 줄 것입니다 :

11.40

유형 이중의 정밀 제한에 대해 실행 중입니다.

Java.Math에는 임의의 차량 산술 시설이 있습니다.

7.3은 이진에 유한 표현이 없기 때문에 할 수 없습니다. 가장 가까운 것은 2054767329987789/2 ** 48 = 7.3+1/1407374883553280입니다.

보세요 http://docs.python.org/tutorial/floatingpoint.html 추가 설명을 위해. (Python 웹 사이트에 있지만 Java와 C ++는 동일한 "문제"를 가지고 있습니다.)

해결책은 정확히 귀하의 문제가 무엇인지에 달려 있습니다.

  • 모든 노이즈 숫자를 보는 것을 좋아하지 않는다면 문자열 형식을 수정하십시오. 15 개 이상의 중요한 숫자 (또는 플로트의 경우 7) 이상 표시하지 마십시오.
  • 숫자의 부정확성이 "if"문장과 같은 것들을 깨는다면, 당신은 if (x == 7.3) 대신 if (abs (x -7.3) <fancerance)를 작성해야합니다.
  • 돈으로 일하고 있다면, 당신이 정말로 원하는 것은 소수점 고정 지점입니다. 정수 수의 센트 또는 통화의 가장 작은 단위를 보관하십시오.
  • (매우 가능성은 거의 없음) 정밀도의 53 개 이상의 중요한 비트 (15-16 숫자)가 필요하다면 Bigdecimal과 같은 고정밀 부동 소수점 유형을 사용하십시오.
private void getRound() {
    // this is very simple and interesting 
    double a = 5, b = 3, c;
    c = a / b;
    System.out.println(" round  val is " + c);

    //  round  val is  :  1.6666666666666667
    // if you want to only two precision point with double we 
            //  can use formate option in String 
           // which takes 2 parameters one is formte specifier which 
           // shows dicimal places another double value 
    String s = String.format("%.2f", c);
    double val = Double.parseDouble(s);
    System.out.println(" val is :" + val);
    // now out put will be : val is :1.67
}

java.math.bigdecimal을 사용하십시오

복식은 내부적으로 이진 분획이므로 때로는 십진수 분획을 정확한 소수점으로 나타낼 수 없습니다.

모든 것을 100으로 곱하고 센트만큼 긴 보관하십시오.

컴퓨터는 바이너리에 숫자를 저장하며 실제로 33.33333333 또는 100.0과 같은 숫자를 실제로 나타내지 못합니다. 이것은 복식 사용에 대한 까다로운 것 중 하나입니다. 사용자에게 표시하기 전에 답을 반올림해야합니다. 운 좋게도 대부분의 응용 프로그램에서, 당신은 어쨌든 소수점 이하의 장소가 필요하지 않습니다.

부동 소수점 번호는 주어진 부동 소수점 번호의 경우 다음으로 더 높은 부동 소수점 수가 있다는 실수와 다릅니다. 정수와 동일합니다. 1과 2 사이에는 정수가 없습니다.

1/3을 플로트로 표현할 방법은 없습니다. 그 아래에 플로트가 있고 그 위에 플로트가 있으며, 그들 사이에 특정 거리가 있습니다. 그리고 1/3은 그 공간에 있습니다.

Java에 대한 Apfloat는 임의의 정밀 부동 소수점 번호로 작동한다고 주장하지만 사용한 적이 없습니다. 아마 볼만한 가치가 있습니다.http://www.apfloat.org/apfloat_java/

이전에 비슷한 질문이있었습니다자바 부동 소수점 고정밀 라이브러리

복식이 있습니다 근사치 Java 소스의 소수점 숫자. 당신은 이중 (이진 코드 값)과 소스 (소수점) 사이의 불일치의 결과를보고 있습니다.

Java는 가장 가까운 이진 근사치를 생성합니다. java.text.decimalformat를 사용하여 더 잘 보이는 소수점 값을 표시 할 수 있습니다.

BigDecimal을 사용하십시오. Round_half_even과 같은 반올림 규칙을 지정할 수 있습니다. 이는 둘 다 같은 거리 인 경우 이웃에게 반올림하여 통계 오류를 최소화합니다. 즉, 1.5와 2.5 라운드에서 2까지 2 개).

BigDecimal을 확인하십시오. 이와 같은 부동 소수점 산술을 다루는 문제를 처리합니다.

새로운 전화는 다음과 같습니다.

term[number].coefficient.add(co);

setScale ()을 사용하여 사용할 소수점 정밀도의 수를 설정하십시오.

수학 클래스의 Round () 메소드를 사용하지 않는 이유는 무엇입니까?

// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4

이중 값을 사용하는 것 외에 다른 선택이없는 경우 아래 코드를 사용할 수 있습니다.

public static double sumDouble(double value1, double value2) {
    double sum = 0.0;
    String value1Str = Double.toString(value1);
    int decimalIndex = value1Str.indexOf(".");
    int value1Precision = 0;
    if (decimalIndex != -1) {
        value1Precision = (value1Str.length() - 1) - decimalIndex;
    }

    String value2Str = Double.toString(value2);
    decimalIndex = value2Str.indexOf(".");
    int value2Precision = 0;
    if (decimalIndex != -1) {
        value2Precision = (value2Str.length() - 1) - decimalIndex;
    }

    int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
    sum = value1 + value2;
    String s = String.format("%." + maxPrecision + "f", sum);
    sum = Double.parseDouble(s);
    return sum;
}

bigdecimal을 사용하여 efford를 낭비하지 마십시오. 99.99999%의 경우 필요하지 않습니다. 자바 더블 유형은 대략적인 코스이지만 거의 모든 경우에 충분히 정확합니다. 14 번째 중요한 자리에 오류가 있습니다. 이것은 정말로 무시할 수 있습니다!

좋은 출력 사용 :

System.out.printf("%.2f\n", total);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top