Java에서 더블로 정밀도 유지
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를 인쇄(또는 사용 가능)할 수 있을까요?
다른 사용자가 언급한 것처럼 11.4를 정확하게 표현하려면 이 클래스를 사용하는 것이 좋습니다.
이 문제가 발생하는 이유에 대해 간단히 설명하겠습니다.
float
★★★★★★★★★★★★★★★★★」double
Java의 원시 유형은 부동 소수점 숫자이며, 여기서 숫자는 분수와 지수의 이진 표현으로 저장됩니다.
값예: 2배 정밀도).double
여기서 type은 64비트입니다.
- 1비트는 부호(양 또는 음)를 나타냅니다.
- 지수의 경우 11비트입니다.
- 유효 자릿수의 경우 52비트(2진수로서의 소수 부분).
'이것들'이 .double
값을 나타냅니다.
Java에서의 부동 소수점 값 처리 방법에 대한 자세한 내용은 섹션 4.2.3: Java 언어 사양의 부동 소수점 유형, 형식 및 값을 참조하십시오.
byte
,char
,int
,long
유형은 고정 소수점 숫자로, 숫자를 정확하게 나타냅니다.고정 소수점 숫자와 달리 부동 소수점 숫자는 정확한 숫자 표현을 반환할 수 없는 경우가 있습니다.이것이 당신이 결국에 하게 되는 이유입니다.11.399999999999
의 5.6 + 5.8
.
1.5나 150.1005와 같이 정확한 값이 필요한 경우 숫자를 정확하게 나타낼 수 있는 고정 소수점 유형 중 하나를 사용해야 합니다.
이미 여러 번 언급했듯이 자바에는 매우 큰 숫자와 매우 작은 숫자를 처리할 수 있는 클래스가 있습니다.
API의 BigDecimal
링크:
불변의 임의의 정밀도 부호 있는 10진수.Big Decimal은 임의의 정밀도 정수 언스케일 값과 32비트 정수 스케일로 구성됩니다.0 또는 양의 경우 스케일은 소수점 오른쪽에 있는 자릿수입니다.음수일 경우 스케일링되지 않은 숫자의 값에 10을 곱하여 스케일 부정의 거듭제곱합니다.따라서 BigDecimal이 나타내는 숫자의 값은 (unscaledValue x 10^-scale)입니다.
스택 오버플로에 대해 부동소수점 숫자와 그 정밀도에 관한 많은 의문이 제기되어 왔습니다.다음은 관심 있는 관련 질문 목록입니다.
- 21.4와 같은 값으로 초기화된 이중 변수가 21.39999618530273으로 표시되는 이유는 무엇입니까?
- 큰 숫자를 C++로 인쇄하는 방법
- 부동 소수점은 어떻게 저장됩니까?언제가 중요합니까?
- 회계 애플리케이션 금액에 부동 또는 소수점 사용
부동소수점 숫자에 대한 자세한 내용은 모든 컴퓨터 과학자가 부동소수점 산술에 대해 알아야 할 사항을 참조하십시오.
,33.33333333333333
취득하는 값은 실제로 가장 가까운 대표 가능한 이중 소수점 값입니다.을 사용하다
33.3333333333333285963817615993320941925048828125
이를 100으로 나누면 다음과 같이 됩니다.
0.333333333333333285963817615993320941925048828125
또한 이중 소수점 숫자로 나타낼 수 없기 때문에 다시 가장 가까운 표현 가능한 값으로 반올림됩니다. 즉, 정확히 다음과 같습니다.
0.3333333333333332593184650249895639717578887939453125
이 값을 인쇄하면 다시 소수점 17자리로 반올림되어 다음과 같은 결과를 얻을 수 있습니다.
0.33333333333333326
값을 분수로 처리하려는 경우 분자와 분모 필드를 포함하는 분율 클래스를 만들 수 있습니다.
덧셈, 뺄셈, 곱셈 및 나눗셈 방법 및 toDouble 방법을 씁니다.이렇게 하면 계산 중에 부동산을 피할 수 있습니다.
편집: 신속한 구현,
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.33333333 * 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.3999999999999999999999911.4이므로 이진수 결과가 소수점 이하만 필요한 값에 매우 가까운 경우 결과가 거의 정확하고 사람이 판독하기 쉬워집니다.
지정하는 정밀도는 수치를 얼마나 계산했는가에 따라 달라집니다.일반적으로 더 많은 오차가 누적되지만 일부 알고리즘은 다른 알고리즘보다 훨씬 빠르게 누적됩니다(반올림 오차에 대해 "안정적"이라고 하는 것이 아니라 "안정적"이라고 불립니다).몇 개의 값을 더하는 것 뿐이라면 소수점 이하 한 자리만 떨어뜨려도 문제가 해결되겠죠.실험.
java의 java.math를 사용하는 것을 검토할 수 있습니다.Big Decimal 클래스(정확한 수학이 필요한 경우)다음은 Big Decimal 사례에 대한 Oracle/Sun의 좋은 기사입니다.누군가가 말한 것처럼 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
}
}
그리고 내가 가장 좋아하는 새로운 언어인 그루비를 소개하자면, 여기 같은 것의 더 좋은 예가 있다.
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
세 줄의 예시로 만들 수도 있었겠죠:)
정확한 정밀도를 원한다면 Big Decimal을 사용합니다.그렇지 않으면 int에 10을 곱한 정밀도를 사용할 수 있습니다.
다른 사람들이 지적했듯이, 10진수는 10의 거듭제곱에 기초하고 2진수는 2의 거듭제곱에 기초하기 때문에 모든 10진수 값을 2진수로 나타낼 수 없습니다.
정밀도가 중요한 경우 Big Decimal을 사용하지만 출력을 원할 경우 다음과 같이 하십시오.
System.out.printf("%.2f\n", total);
제공 내용:
11.40
당신은 이중 타입의 정밀도 한계에 부딪히고 있습니다.
Java.Math에는 몇 가지 임의 정밀도 산술 기능이 있습니다.
7.3은 2진수로 한정되어 있지 않기 때문에 할 수 없습니다.가장 가까운 값은 20547673299878789/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) < TRANCE (공차)를 써야 합니다.
- 만약 당신이 돈을 가지고 일한다면, 아마도 당신이 정말로 원하는 것은 십진수 고정점일 것이다.정수 센트 또는 통화의 가장 작은 단위를 저장하십시오.
- (매우 있음직하지 않음) 53비트 이상의 정밀도가 필요한 경우 Big Decimal 등의 고정밀 부동소수점 유형을 사용합니다.
java.math를 사용합니다.빅데시멀
곱셈은 내부적으로 2진수이므로 소수점 이하를 정확하게 나타낼 수 없는 경우가 있습니다.
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
}
/*
0.8 1.2
0.7 1.3
0.7000000000000002 2.3
0.7999999999999998 4.2
*/
double adjust = fToInt + 1.0 - orgV;
// The following two lines works for me.
String s = String.format("%.2f", adjust);
double val = Double.parseDouble(s);
System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8
모든 것에 100을 곱해서 1센트에 저장하세요.
컴퓨터는 숫자를 이진수로 저장하며 실제로 33.33333333이나 100.0과 같은 숫자를 정확하게 나타낼 수는 없습니다.이것은 더블을 사용할 때 까다로운 점 중 하나입니다.사용자에게 보여주기 전에 반올림만 하면 됩니다.다행히 대부분의 응용 프로그램에서는 소수점 이하 자리는 필요 없습니다.
부동소수점 번호는 임의의 부동소수점 번호에 대해 다음으로 높은 부동소수점 번호가 있다는 점에서 실제 숫자와 다릅니다.정수와 같다.1과 2 사이에는 정수가 없습니다.
1/3을 플로트로 나타낼 수 있는 방법은 없습니다.그 아래에는 부표가 있고 그 위에는 부표가 있고 그들 사이에는 일정한 거리가 있습니다.1/3은 이 공간에 있습니다.
자바용 Apfloat는 임의의 정밀 부동소수점수로 동작한다고 주장하지만, 저는 그것을 사용한 적이 없습니다.아마 볼만 하겠지.http://www.apfloat.org/apfloat_java/
Java 부동소수점 고정밀 라이브러리 이전에도 비슷한 질문이 있었습니다.
간단한 답변:항상 BigDecimal을 사용하고 생성자를 이중 인수가 아닌 String 인수로 사용해야 합니다.
예시로 돌아가면 다음 코드는 원하는 대로 11.4를 인쇄합니다.
public class doublePrecision {
public static void main(String[] args) {
BigDecimal total = new BigDecimal("0");
total = total.add(new BigDecimal("5.6"));
total = total.add(new BigDecimal("5.8"));
System.out.println(total);
}
}
배수는 Java 소스의 10진수 근사치입니다.이중(이진수 코드 값)과 소스(10진수 코드 값)의 불일치의 결과를 확인할 수 있습니다.
자바는 가장 가까운 이진수 근사치를 만들어냅니다.java.text를 사용할 수 있습니다.[ Decimal Format ]를 선택하면, 보다 보기 좋은 10 진수의 값이 표시됩니다.
Big Decimal 을 사용합니다.또한 반올림 규칙을 지정할 수도 있습니다(ROUND_HALF_EVEN 등). 양쪽이 같은 거리인 경우 짝수 인접 라우터로 반올림하여 통계 오류를 최소화할 수 있습니다(즉, 1.5와 2.5 모두 2로 반올림).
수학 수업에서 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
BigDecimal을 보세요. 이렇게 부동 소수점 산술 문제를 처리합니다.
새로운 콜은 다음과 같습니다.
term[number].coefficient.add(co);
setScale()을 사용하여 사용할 소수점 이하 정밀도를 설정합니다.
이중값을 사용하는 것 외에 다른 선택사항이 없는 경우 아래 코드를 사용할 수 있습니다.
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;
}
다음을 수행할 수 있습니다.
System.out.println(String.format("%.12f", total));
여기서 소수점 값을 변경하면 %.12f.
Big Decimal을 사용하여 당신의 능력을 낭비하지 마세요.99.99999%의 경우 필요 없습니다.java double type은 거의 비슷하지만 거의 모든 경우 충분히 정밀합니다.의 14번째 유효 자릿수에 오류가 있음을 유의하십시오.이건 정말 무시해도 될 정도야!
적절한 출력을 얻으려면 다음을 사용합니다.
System.out.printf("%.2f\n", total);
언급URL : https://stackoverflow.com/questions/322749/retain-precision-with-double-in-java
'programing' 카테고리의 다른 글
Vuex 및 Firebase 저장소 상태 오류 (0) | 2022.07.04 |
---|---|
extern inline은 무엇을 합니까? (0) | 2022.07.04 |
@vue/cli(vue-cli) 프로젝트에서 농담 경고를 비활성화하시겠습니까? (0) | 2022.07.04 |
포인터 또는 주소를 인쇄할 올바른 형식 지정자입니까? (0) | 2022.07.04 |
Vuex의 동적 변경 값 감시 (0) | 2022.07.04 |