태그 보관물: precision

precision

float와 double의 차이점은 무엇입니까? double하나를 사용하여 즉, 상호 교환 보이거나 다른

배정 밀도와 단 정밀도의 차이점에 대해 읽었습니다. 그러나 대부분의 경우, float그리고 double하나를 사용하여 즉, 상호 교환 보이거나 다른 하나는 결과에 영향을 미칠 것 같지 않습니다. 이것이 사실입니까? 수레와 복식은 언제 교환 할 수 있습니까? 그들 사이의 차이점은 무엇입니까?



답변

큰 차이.

이름에서 알 수 있듯이 a double의 정밀도는 [1] 의 2 배 입니다. 일반적으로 a 는 십진수 15 자리이며, 7은 7입니다.floatdoublefloat

자릿수 계산 방법은 다음과 같습니다.

double52 가수 비트 + 1 숨겨진 비트 : log (2 53 ÷÷ log (10) = 15.95 자리

float23 개의 가수 비트 + 1 개의 숨겨진 비트 : log (2 24 ÷÷ log (10) = 7.22 자리

이 정밀 손실로 인해 반복 계산을 수행 할 때 더 큰 잘림 오류가 누적 될 수 있습니다.

float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.7g\n", b); // prints 9.000023

동안

double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.15g\n", b); // prints 8.99999999999996

또한 float의 최대 값은 약 3e38이지만 double은 약 1.7e308이므로를 사용 float하면 “인피니티”(예 : 특수 부동 소수점 숫자)를 double간단한 것보다 훨씬 쉽게 맞출 수 있습니다 (예 : 계승 60 계산).

테스트하는 동안 소수의 테스트 사례에 이러한 큰 숫자가 포함되어있을 수 있으며 플로트를 사용하면 프로그램이 실패 할 수 있습니다.


물론 때로는 double충분히 정확 하지도 않기 때문에 때때로 우리는 long double[1] (위의 예는 Mac에서 9.000000000000000066을 나타냄)을 갖지만 모든 부동 소수점 유형은 반올림 오류를습니다 . 따라서 정밀도가 매우 중요한 경우 (예 : 돈) 처리) int또는 분수 클래스 를 사용해야합니다 .


또한 +=오류가 빠르게 누적되므로 많은 부동 소수점 수를 합산 하는 데 사용하지 마십시오 . Python을 사용하는 경우을 사용하십시오 fsum. 그렇지 않으면 Kahan summation 알고리즘 을 구현하십시오 .


[1] : C 및 C ++ 표준은 float, double및 의 표현을 지정하지 않습니다 long double. 세 가지 모두 IEEE 배정 밀도로 구현 될 수 있습니다. 그럼에도 불구하고, 대부분의 아키텍처 (GCC, MSVC, 86, 64, ARM은) float 입니다 실제로 소수점 수 (binary32)를 부동 IEEE 단 정밀도하고 double 있다 IEEE 배정 밀도 부동 소수점 숫자 (binary64).


답변

표준 C99 (ISO-IEC 9899 6.2.5 §10) 또는 C ++ 2003 (ISO-IEC 14882-2003 3.1.9 §8) 표준은 다음과 같습니다.

부동 소수점 유형 float에는 double, 및 , 세 가지가 있습니다 long double. 타입 double은 최소한 정밀도를 제공 float하고 타입 long double은 최소한 정밀도를 제공 double합니다. 유형의 값 세트는 유형의 값 세트의 float서브 세트입니다 double. 유형의 값 세트는 유형의 값 세트의 double서브 세트입니다 long double.

C ++ 표준은 다음을 추가합니다.

부동 소수점 유형의 값 표현은 구현 정의됩니다.

IEEE 부동 소수점 표준을 심도있게 다루는 모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 훌륭한 점을 살펴볼 것을 제안 합니다. 표현 세부 사항에 대해 배우고 크기와 정밀도 사이에 상충 관계가 있음을 알게됩니다. 부동 소수점 표현의 정밀도는 크기가 감소함에 따라 증가하므로 -1과 1 사이의 부동 소수점 숫자는 가장 정밀한 숫자입니다.


답변

이차 방정식을 감안할 : X 2  – 4.0000000  X  + 3.9999999 = 0, 정확한 뿌리 10의 유효 숫자는, R 1  = 2.000316228 및 R 2  = 1.999683772.

floatand를 사용 double하여 테스트 프로그램을 작성할 수 있습니다.

#include <stdio.h>
#include <math.h>

void dbl_solve(double a, double b, double c)
{
    double d = b*b - 4.0*a*c;
    double sd = sqrt(d);
    double r1 = (-b + sd) / (2.0*a);
    double r2 = (-b - sd) / (2.0*a);
    printf("%.5f\t%.5f\n", r1, r2);
}

void flt_solve(float a, float b, float c)
{
    float d = b*b - 4.0f*a*c;
    float sd = sqrtf(d);
    float r1 = (-b + sd) / (2.0f*a);
    float r2 = (-b - sd) / (2.0f*a);
    printf("%.5f\t%.5f\n", r1, r2);
}

int main(void)
{
    float fa = 1.0f;
    float fb = -4.0000000f;
    float fc = 3.9999999f;
    double da = 1.0;
    double db = -4.0000000;
    double dc = 3.9999999;
    flt_solve(fa, fb, fc);
    dbl_solve(da, db, dc);
    return 0;
}  

프로그램을 실행하면 다음이 제공됩니다.

2.00000 2.00000
2.00032 1.99968

숫자는 크지 않지만 여전히을 사용하여 취소 효과를 얻을 수 float있습니다.

(실제로 위의 방법은 단 정밀도 또는 배정 밀도 부동 소수점 숫자를 사용하여 2 차 방정식을 푸는 가장 좋은 방법은 아니지만 보다 안정적인 방법을 사용하더라도 답은 변하지 않습니다 .)


답변

  • double은 64이고 single precision (float)은 32 비트입니다.
  • double은 더 큰 가수 (실수의 정수 비트)를 갖습니다.
  • 부정확 한 부분은 두 배로 작습니다.

답변

부동 소수점 계산과 관련된 숫자의 크기는 가장 관련성이 없습니다. 수행되는 계산은 관련이 있습니다.

본질적으로 계산을 수행하고 결과가 비합리적인 숫자 또는 반복되는 10 진수 인 경우 해당 숫자가 사용중인 유한 크기 데이터 구조로 스쿼시되면 반올림 오류가 발생합니다. double은 float의 두 배 크기이므로 반올림 오류가 훨씬 작습니다.

테스트는 특히 이런 종류의 오류를 유발하는 숫자를 사용할 수 있으므로 코드에서 적절한 유형을 사용했는지 테스트했습니다.


답변

32 비트 길이의 float 유형은 정밀도가 7 자리입니다. 매우 크거나 아주 작은 범위 (+/- 3.4 * 10 ^ 38 또는 * 10 ^ -38)의 값을 저장할 수 있지만 유효 숫자는 7 자리입니다.

64 비트 길이의 double 유형은 더 큰 범위 (* 10 ^ + /-308)와 15 자리 정밀도를 갖습니다.

long double 타입은 명목상 80 비트이지만 주어진 컴파일러 / OS 쌍은 정렬을 위해 12-16 바이트로 저장할 수 있습니다. long double에는 엄청나게 큰 지수가 있으며 19 자리의 정밀도를 가져야합니다. Microsoft는 무한한 지혜로 long double을 8 바이트로 제한하며 일반 double과 동일합니다.

일반적으로 부동 소수점 값 / 변수가 필요할 때 double 유형을 사용하십시오. 표현식에 사용 된 리터럴 부동 소수점 값은 기본적으로 더블로 처리되며 부동 소수점 값을 반환하는 대부분의 수학 함수는 더블을 반환합니다. 두 번만 사용하면 많은 두통과 타입 캐스팅을 줄일 수 있습니다.


답변

방금 나를 알아 내고 실수로 플로트 정밀도의 좋은 예를 줄 수있는 오류가 발생했습니다.

#include <iostream>
#include <iomanip>

int main(){
  for(float t=0;t<1;t+=0.01){
     std::cout << std::fixed << std::setprecision(6) << t << std::endl;
  }
}

출력은

0.000000
0.010000
0.020000
0.030000
0.040000
0.050000
0.060000
0.070000
0.080000
0.090000
0.100000
0.110000
0.120000
0.130000
0.140000
0.150000
0.160000
0.170000
0.180000
0.190000
0.200000
0.210000
0.220000
0.230000
0.240000
0.250000
0.260000
0.270000
0.280000
0.290000
0.300000
0.310000
0.320000
0.330000
0.340000
0.350000
0.360000
0.370000
0.380000
0.390000
0.400000
0.410000
0.420000
0.430000
0.440000
0.450000
0.460000
0.470000
0.480000
0.490000
0.500000
0.510000
0.520000
0.530000
0.540000
0.550000
0.560000
0.570000
0.580000
0.590000
0.600000
0.610000
0.620000
0.630000
0.640000
0.650000
0.660000
0.670000
0.680000
0.690000
0.700000
0.710000
0.720000
0.730000
0.740000
0.750000
0.760000
0.770000
0.780000
0.790000
0.800000
0.810000
0.820000
0.830000
0.839999
0.849999
0.859999
0.869999
0.879999
0.889999
0.899999
0.909999
0.919999
0.929999
0.939999
0.949999
0.959999
0.969999
0.979999
0.989999
0.999999

0.83 이후에 볼 수 있듯이 정밀도는 크게 떨어집니다.

그러나 t이중으로 설정하면 이러한 문제가 발생하지 않습니다.

이 사소한 오류를 깨닫는 데 5 시간이 걸렸으며 이로 인해 프로그램이 손상되었습니다.