[c++] 엡실론을 사용하여 double을 0으로 비교

오늘은 C ++ 코드 (다른 사람이 작성)를 살펴 보고이 섹션을 찾았습니다.

double someValue = ...
if (someValue <  std::numeric_limits<double>::epsilon() &&
    someValue > -std::numeric_limits<double>::epsilon()) {
  someValue = 0.0;
}

이것이 의미가 있는지 알아 내려고 노력 중입니다.

에 대한 설명서 epsilon()는 다음과 같습니다.

이 함수는 1과 1보다 큰 가장 작은 값의 차이 (더블로 표시)를 반환합니다.

이것은 0에도 적용됩니까, 즉 epsilon()가장 작은 값이 0보다 큽니까? 또는 사이이 번호는 00 + epsilon그가에 의해 표현 될 수있다 double?

그렇지 않으면 비교가 someValue == 0.0?에 해당하지 않습니까?



답변

64 비트 IEEE double을 가정하면 52 비트 가수와 11 비트 지수가 있습니다. 비트로 나누자 :

1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^0 = 1

1보다 큰 가장 작은 표현 가능 숫자

1.0000 00000000 00000000 00000000 00000000 00000000 00000001 × 2^0 = 1 + 2^-52

따라서:

epsilon = (1 + 2^-52) - 1 = 2^-52

0에서 엡실론 사이의 숫자가 있습니까? Plenty … 예를 들어 최소 양수 (정상) 숫자는 다음과 같습니다.

1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^-1022 = 2^-1022

실제로 (1022 - 52 + 1)×2^52 = 43729952381767516160과 엡실론 사이의 숫자 가 있으며 이는 모든 양의 표현 가능한 숫자의 47 %입니다 …


답변

테스트는 확실히 동일하지 않습니다 someValue == 0. 부동 소수점 숫자의 전체 아이디어는 지수와 의미를 저장한다는 것입니다. 따라서 특정 수의 이진 유효 정밀도 수치 (IEEE double의 경우 53)로 값을 나타냅니다. 표현 가능한 값은 1에 비해 0에 훨씬 더 밀집되어 있습니다.

보다 친숙한 10 진수 시스템을 사용하려면 지수와 함께 “4 자리 유효 숫자까지”10 진수 값을 저장한다고 가정하십시오. 그런 다음 표현할 수있는 값보다 크 1입니다 1.001 * 10^0, 그리고 epsilon이다 1.000 * 10^-3. 그러나 1.000 * 10^-4지수가 -4를 저장할 수 있다고 가정하면 표현할 수 있습니다. IEEE double 은의 지수보다 적은 지수 저장할 수 있다는 내 말을들 있습니다 epsilon.

이 코드만으로는 epsilon구체적으로 바운드 로 사용하는 것이 타당한 지 여부를 알 수 없으므로 컨텍스트를 살펴 봐야합니다. 그것은 그 수있다 epsilon생성 된 계산의 오차의 적절한 추정치 someValue, 그리고 그렇지 않은 것일 수있다.


답변

epsilon은 1과 1보다 위에 표시 될 수있는 다음으로 가장 높은 숫자의 차이이며 0과 0보다 높게 표시 될 수있는 다음으로 가장 높은 숫자와의 차이가 아니기 때문에 0과 엡실론 사이에 존재하는 숫자가 있습니다. 코드는 거의 수행하지 않습니다) :-

#include <limits>

int main ()
{
  struct Doubles
  {
      double one;
      double epsilon;
      double half_epsilon;
  } values;

  values.one = 1.0;
  values.epsilon = std::numeric_limits<double>::epsilon();
  values.half_epsilon = values.epsilon / 2.0;
}

디버거를 사용하여 main의 끝에서 프로그램을 중지하고 결과를 보면 epsilon / 2가 epsilon, 0 및 1과 다르다는 것을 알 수 있습니다.

따라서이 함수는 +/- epsilon 사이의 값을 취하여 0으로 만듭니다.


답변

다음 프로그램을 사용하여 숫자 (1.0, 0.0, …) 주위의 엡실론 (가장 작은 차이)의 근사값을 인쇄 할 수 있습니다. 다음과 같은 결과를 출력합니다.
epsilon for 0.0 is 4.940656e-324
epsilon for 1.0 is 2.220446e-16
약간 생각하면 지수가 해당 숫자의 크기에 맞게 조정할 수 있기 때문에 엡실론 값을 보는 데 사용하는 숫자가 엡실론의 크기가 작을수록 작아집니다.

#include <stdio.h>
#include <assert.h>
double getEps (double m) {
  double approx=1.0;
  double lastApprox=0.0;
  while (m+approx!=m) {
    lastApprox=approx;
    approx/=2.0;
  }
  assert (lastApprox!=0);
  return lastApprox;
}
int main () {
  printf ("epsilon for 0.0 is %e\n", getEps (0.0));
  printf ("epsilon for 1.0 is %e\n", getEps (1.0));
  return 0;
}


답변

16 비트 레지스터에 맞는 장난감 부동 소수점 숫자로 작업한다고 가정합니다. 부호 비트, 5 비트 지수 및 10 비트 가수가 있습니다.

이 부동 소수점 숫자의 값은 가수이며 2 진 10 진수 값으로 해석되며 지수의 거듭 제곱에 2를 곱한 값입니다.

1 주위의 지수는 0과 같습니다. 가수의 가장 작은 숫자는 1024의 일부입니다.

지수의 1/2에 가까운 지수는 -1이므로 가수의 가장 작은 부분은 절반입니다. 5 비트 지수를 사용하면 음수 16에 도달 할 수 있으며, 가수의 가장 작은 부분은 32m에서 한 부분의 가치가 있습니다. 그리고 음수 16 지수에서 값은 32k에서 한 부분 정도이며 위에서 계산 한 엡실론보다 0에 훨씬 가깝습니다!

이제 이것은 실제 부동 소수점 시스템의 모든 단점을 반영하지 않는 장난감 부동 소수점 모델이지만 엡실론보다 작은 값을 반영하는 기능은 실제 부동 소수점 값과 상당히 유사합니다.


답변

차이 X및 다음의 값 X에 따라 변화 X. 의 다음 값과
epsilon()의 차이점 1입니다 1. 와 다음 값의
차이 는 없습니다 .00epsilon()

대신 다음 std::nextafter0같이 double 값을 비교하는 데 사용할 수 있습니다 .

bool same(double a, double b)
{
  return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
    && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}

double someValue = ...
if (same (someValue, 0.0)) {
  someValue = 0.0;
}


답변

컴퓨터 의 정확성 에 달려 있다고 생각 합니다. 이 표를 살펴보십시오 : 엡실론이 두 배로 표시되지만 정밀도가 높으면 비교가

someValue == 0.0

어쨌든 좋은 질문입니다!