IT TIP

플로트에 가능한 가장 작은 플로트 추가

itqueen 2020. 12. 6. 22:26
반응형

플로트에 가능한 가장 작은 플로트 추가


float의 가능한 가장 작은 값을 float에 추가하고 싶습니다. 예를 들어 1.0 + 가능한 가장 작은 부동 소수점을 얻기 위해 이렇게 시도했습니다.

float result = 1.0f + std::numeric_limits<float>::min();

그러나 그렇게하면 다음과 같은 결과가 나타납니다.

(result > 1.0f) == false
(result == 1.0f) == true

Visual Studio 2015를 사용하고 있습니다. 왜 이런 일이 발생합니까? 이 문제를 해결하려면 어떻게해야합니까?


1 이후의 다음 표현 가능한 값을 원하면 헤더 std::nextafter에서 라는 함수가 <cmath>있습니다.

float result = std::nextafter(1.0f, 2.0f);

두 번째 인수의 방향으로 첫 번째 인수에서 시작하여 다음 표현 가능한 값을 반환합니다. 따라서 1 미만의 다음 값을 찾으려면 다음을 수행 할 수 있습니다.

float result = std::nextafter(1.0f, 0.0f);

가장 작은 양의 표현 가능 값을 1에 추가하는 것은 1과 다음 표현 가능 값의 차이가 0과 다음 표현 가능 값의 차이보다 크기 때문에 작동하지 않습니다.


당신이 관찰하고있는 "문제" 는 부동 소수점 산술의 특성 때문입니다 .

FP에서 정밀도는 규모에 따라 다릅니다. 값 주위에 1.0정밀도가 구별 할 수있을 것만으로는 충분하지 않습니다 1.01.0+min_representable경우 min_representable0보다 작은 가능한 값이 큰 (우리는 단지 작은 정규화 된 수를 고려하는 경우에도이 std::numeric_limits<float>::min()... 가장 작은 비정규은 크기가 작은 또 다른 몇 가지 주문입니다).

이중 정밀도 예를 들어 규모의 주위에, IEEE754 부동 소수점 숫자를 64 비트 x=10000000000000000(10 (16) 가 구별하는 것은 불가능합니다) xx+1.


스케일에 따라 해상도가 변한다는 사실은 소수점이 "부동"하기 때문에 "부동 소수점"이라는 이름의 바로 그 이유입니다. 고정 소수점 표현은 대신 고정 해상도를 갖습니다 (예를 들어 단위보다 16 개의 이진수를 사용하면 정밀도는 1/65536 ~ 0.00001입니다).

예를 들어, IEEE754 32 비트 부동 소수점 형식에는 부호에 대해 1 비트, 지수에 대해 8 비트, 가수에 대해 31 비트가 있습니다.

부동 소수점


최소값 eps같은 1.0f + eps != 1.0f미리 정의 된 상수 가능 FLT_EPSILON하거나 std::numeric_limits<float>::epsilon. 엡실론이 반올림 오류와 어떻게 관련되는지 논의하는 Wikipedia의 machine epsilon을 참조하십시오 .

즉 엡실론은 여기에서 예상했던 작업을 수행하는 가장 작은 값으로 1.0에 추가 할 때 차이를 만듭니다.

보다 일반적인 버전 (1.0이 아닌 숫자의 경우)은 가수의 마지막 위치에서 1 단위라고합니다. Wikipedia의 ULP 기사를 참조하십시오 .


minA (정규화 형태) 플로트 2 둘레, 즉 것을 가정 할 수있는 최소의 비 - 제로 값 -126 (-126이 플로트에 대한 최소 허용 지수된다); 이제 그것을 1로 더하면 여전히 1을 얻게 될 것입니다. a float는 가수가 23 비트에 불과하기 때문입니다. 따라서 이러한 작은 변화는 "큰"숫자로 표현할 수 없습니다 (이를 보려면 126 비트 가수가 필요합니다. 합산 2 -126 을 1로 변경 ).

1로 변경 가능한 최소 대신 인 epsilon사실 2 (소위 계산기 엡실론) -23 은 가수의 마지막 비트 영향으로 -.


부동 소수점 값을 가능한 한 최소로 늘리거나 줄이려면 nextafter+/-를 사용하십시오 infinity().

을 사용하면 무한대 인 next_after(x,std::numeric_limits::max())경우 결과가 잘못됩니다 x.

#include <iostream>
#include <limits>
#include <cmath>

template<typename T>
T next_above(const T& v){
    return std::nextafter(v,std::numeric_limits<T>::infinity()) ;
}
template<typename T>
T next_below(const T& v){
    return std::nextafter(v,-std::numeric_limits<T>::infinity()) ;
}

int main(){
  std::cout << "eps   : "<<std::numeric_limits<double>::epsilon()<< std::endl; // gives eps

  std::cout << "after : "<<next_above(1.0) - 1.0<< std::endl; // gives eps (the definition of eps)
  std::cout << "below : "<<next_below(1.0) - 1.0<< std::endl; // gives -eps/2

  // Note: this is what next_above does:
  std::cout << std::nextafter(std::numeric_limits<double>::infinity(),
     std::numeric_limits<double>::infinity()) << std::endl; // gives inf

  // while this is probably not what you need:
  std::cout << std::nextafter(std::numeric_limits<double>::infinity(),
     std::numeric_limits<double>::max()) << std::endl; // gives 1.79769e+308

}

참고 URL : https://stackoverflow.com/questions/41317661/adding-smallest-possible-float-to-a-float

반응형