플로트에 가능한 가장 작은 플로트 추가
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.0
및 1.0+min_representable
경우 min_representable
0보다 작은 가능한 값이 큰 (우리는 단지 작은 정규화 된 수를 고려하는 경우에도이 std::numeric_limits<float>::min()
... 가장 작은 비정규은 크기가 작은 또 다른 몇 가지 주문입니다).
이중 정밀도 예를 들어 규모의 주위에, IEEE754 부동 소수점 숫자를 64 비트 x=10000000000000000
(10 (16) 가 구별하는 것은 불가능합니다) x
및 x+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 기사를 참조하십시오 .
min
A (정규화 형태) 플로트 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
'IT TIP' 카테고리의 다른 글
setLatestEventInfo 메서드를 확인할 수 없습니다. (0) | 2020.12.06 |
---|---|
'isPresent ()'확인없이 'Optional.get ()' (0) | 2020.12.06 |
WPF 응용 프로그램을 전체 화면으로 만들기 (표지 시작 메뉴) (0) | 2020.12.06 |
Python에서 rm -rf를 사용하는 가장 쉬운 방법 (0) | 2020.12.04 |
`[super viewDidLoad]`규칙 (0) | 2020.12.04 |