C++에서 double 부동 소수점 정밀도 손실 에 대한 심도 있 는 분석
long a=123456; //assign any long number here
double db=a;
long b=db;
printf("%s
",a==b?"true":"false");
그러나 롱 롱 이나 win 64 의 포인터 주소 등 8 바이트 의 정 수 는 정밀도 가 없어 지기 때문에 이 방면 에 대해 간단 한 테스트 를 실시 했다.
#include<iostream>
#include<stdlib.h>
void showEncodeOfDouble(unsigned char* db){
const int ByteLength=8;
for(int i=ByteLength-1;i>=0;i--)
printf(" %.2x",db[i]);
printf("
");
}
int main(){
unsigned long long maxULL=0xffffffffffffffff; //2^64-1=18446744073709551615,
//max unsigned long long
printf("%llu
",maxULL);
double d1=maxULL; //20bit Significant,Precision Loss
printf("%f
",d1);
maxULL=d1;
printf("%llu
",maxULL);
showEncodeOfDouble((unsigned char*)&d1);
system("pause");
return 0;
}
출력 결 과 는 다음 과 같 습 니 다(visual studio,win 32).18446744073709551615
18446744073709552000.000000
9223372036854775808
43 f0 00 00 00 00 00 00
이로써 두 가지 의문 이 생 겼 다.
1)왜 정밀 도 를 잃 어 버 린 후 얻 은 double 수 는 18446744073709552000.00000 입 니까?
2)왜 double 수 를 unsigned long 으로 다시 바 꾼 후에 얻 은 수 는 double 과 일치 하지 않 습 니까?
이 두 가지 문제 에 대해 서 는 C+부동 소수점 의 규격 에 대해 어느 정도 알 아야 한다.
1 IEEE 부동 소수점 표준
C/C++는 IEEE 부동 소수점 기준 을 사용 하 는데'이 진 과학 표현 법'으로 작은 수 를 표시 합 니 다.
그 중에서 M 은 정수 부분 에 한 자리 만 있 는 이 진 소수 이다.예 를 들 어 1.011 은 10 진법 의 1.375 를 나타 낸다.E 는 이 소수 가 2 를 밑 으로 할 때의 단 계 를 나타 낸다.이상 의 표현 방식 을 바탕 으로 소 수 는 세 부분 을 인 코딩 해 야 한다.기 호 를 나타 내 는 s 와 단계 코드 E,꼬리 코드 M 이다.C++의 double 형식 세 가지 인 코딩 이 차지 하 는 자릿수 는 그림 과 같다.
53 비트 꼬리 디지털 이 도달 할 수 있 는 정밀 도 는 53 2 진법 으로 약 16 개의 10 진법(53 log 10(2)≈15.955)이다.[1]꼬리 디지털 의 인 코딩 에는 숨겨 진 시작 정수 1(또는 0,11 개의 단계 코드 가 0 일 때)이 있 기 때문에 실제 적 으로 15-17 비트 10 진법 의 정밀 도 를 얻 을 수 있다.유효 자릿수 최대 15 비트 의 10 진수 가 double 로 바 뀌 었 다가 원래 의 10 진수 형식 으로 다시 바 뀌 었 을 때 수치 가 일치 합 니 다.다른 한편,하나의 double 수 를 17 자리 이상 의 유효 숫자 를 수용 할 수 있 는 10 진수 로 바 꾸 고 다시 double 로 바 꾸 면 결과 수치 도 일치 합 니 다.
이 는 4 바이트 의 정수 가 double 로 바 뀌 면 일치(2^32=4294967296 은 10 개의 유효 비트)를 유지 할 수 있 고 8 바이트 의 정 수 는 정밀도(2^64-1=18446744073709551615 총 20 개의 유효 비트)를 잃 을 수 있 는 이 유 를 설명 한다.그러나 첫 번 째 문제 에서 정수 가 정 도 를 잃 어 버 린 후에 더 블 수치 로 바 뀌 는 것 은 어떻게 된 것 일 까?이것 은 C++단계 코드 와 꼬리 수가 더 블 수치 에 대한 의 미 를 알 아야 한다.
2 단계 코드 인 코딩 과 끝자리 인 코딩
단계 코드 인 코딩 에서 상수 편향 량 Bias=1023 이 있 습 니 다.11 비트 단계 코드 가 대표 하 는 부호 없 는 정수 치 를 e 로 가정 합 니 다.
1)e 가 0(11 자리 가 모두 1 일 때 특수 숫자 를 표시 하 는 데 사용 되 지 않 으 면 double 수 치 는?
2)e=0 이면 작은 수 치 는?
그러면 함수 showEncodeOfDouble 을 볼 수 있 습 니 다.그 역할 은 double 수의 인 코딩 을 바이트 에 따라 인쇄 하 는 것 입 니 다(왼쪽 은 높 은 바이트).인쇄 결 과 를 위 에서 계산 하면 double 인 코딩 값 이 2^64 를 나타 내 는 것 을 알 수 있 습 니 다.이것 은 합 리 적 입 니 다.정밀도 가 높 은 정 수 를 double 로 바 꿀 때 C+는 짝수 에 반올림 하 는 방식 으로 가장 가 까 운 값 을 얻 을 수 있 습 니 다[2].인쇄 된 결 과 는 C++부동 소수점 인쇄 에 있 는 자세 한 문제 입 니 다.
3 C++부동 소수점 인쇄
많은 C/C++라 이브 러 리 에서 double 을 출력 할 때 출력 결 과 를 짧게 만 들 려 고 합 니 다.C 의 printf 나 cout 를 직접 사용 하여 double 수 를 인쇄 할 때 인쇄 결과 가 정밀도 가 있 는 결과 일 수도 있 습 니 다.16 진법 으로 더 정확 한 double 을 출력 할 수 있 습 니 다.
printf("%a
",d1);
출력 결과:
0x1.000000p+64
이 문제 1 은 사실상 C++에서 고정 밀 정 수 를 double 로 돌 릴 때의 짝수 반올림 문제 일 뿐이다.문제 2 에 대해 서 는 float 나 double 에서 int 로 바 뀌 면 값 이 0 으로 반올림 됩 니 다.예 를 들 어 1.999 는 1 로 바 뀌 고-1.999 는-1 로 바 뀝 니 다.더 나 아가 값 이 넘 칠 수 있다.C 언어 표준 은 이러한 상황 에 대해 고정된 결 과 를 지적 하지 않 았 는데 이런 전환 행 위 는 정의 가 없다.
참조 링크:
[1] http://en.wikipedia.org/wiki/Double-precision_floating-point_format#cite_note-whyieee-1
[2]컴퓨터 시스템 을 깊이 이해 하고 Randal E.Bryant,기계공 업 출판사
[3]http://stackoverflow.com/questions/4738768/printing-double-without-losing-precision
C++에서 double 부동 소수점 정밀도 손실 에 대한 심도 있 는 분석 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 관련 C+double 부동 소수점 정밀도 손실 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
gson이 Integer를 기본적으로 Double로 변환하는 문제를 완벽하게 해결우선 javascript는 다음과 같은 유형만 있습니다. 1. JavaScript의 Number 이중 정밀도 부동 소수점 형식 2. String 큰따옴표의 백슬래시 의미의 유니코드 3. Boolean true 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.