numeric_limits Machine Epsilon이 1 + e> 1 조건을 충족하지 않는 이유는 무엇입니까?
내가 틀리지 않았다면 Machine Epsilon의 정의는 조건을 충족하는 가장 낮은 숫자입니다.
나는 이것을 사용하여 테스트하려고 std::numeric_limits<float>::epsilon()
했지만 이전 부동 소수점 수를 얻으려고하면 값이 만족스럽지 않습니다 std::nextafter
.
#include <cmath>
#include <iostream>
#include <limits>
int main() {
float e = std::numeric_limits<float>::epsilon();
float previous = std::nextafter(e, -std::numeric_limits<float>::infinity());
std::cout << std::boolalpha << ((1.0f + previous) > 1.0f) << std::endl;
return 0;
}
이 스틸 출력 true
https://coliru.stacked-crooked.com/a/841e19dafcf0bf6f.
사용하여 번호를 얻으려고 시도한 후 std::nextafter
적절한 Machine Epsilon이 다음과 같아야한다는 것을 알았습니다.
std::nextafter(std::numeric_limits<float>::epsilon() / 2.0f, std::numeric_limits<float>::infinity())
이 코드를 사용하여 테스트했습니다.
#include <cmath>
#include <iostream>
#include <limits>
bool verify(float e) {
return ((1.0f + e) > 1.0f);
}
int main() {
std::cout.precision(std::numeric_limits<float>::digits);
std::cout << std::boolalpha << std::fixed;
float epsilon = std::numeric_limits<float>::epsilon();
float last = epsilon;
while (true) {
last = std::nextafter(last, -std::numeric_limits<float>::infinity());
if ((1.0f + last) > 1.0f) {
epsilon = last;
} else {
break;
}
}
// Does not satisfy condition
std::cout << "last: " << verify(last) << " " << last << std::endl;
// Satisfy condition
std::cout << "epsilon: " << verify(epsilon) << " " << epsilon << std::endl;
float half_epsilon = std::numeric_limits<float>::epsilon() / 2.0f;
float actual_epsilon = std::nextafter(half_epsilon, std::numeric_limits<float>::infinity());
// Same as 'last' at this point
std::cout << "half_epsilon: " << verify(half_epsilon) << " " << half_epsilon << std::endl;
// Same as 'epsilon' at this point
std::cout << "actual_epsilon: " << verify(actual_epsilon) << " " << actual_epsilon << std::endl;
return 0;
}
이 출력
last: false 0.000000059604644775390625
epsilon: true 0.000000059604651880817983
half_epsilon: false 0.000000059604644775390625
actual_epsilon: true 0.000000059604651880817983
https://coliru.stacked-crooked.com/a/3c66a2144e80a91b
내가 여기서 somethig를 놓치고 있습니까?
답변
내가 틀리지 않았다면 Machine Epsilon의 정의는 조건을 만족하는 가장 낮은 숫자입니다. [
1 + epsilon > 1
]
닫았지만 C ++의 맥락에서 틀 렸습니다. (나는 당신의 정의가 다른 학문적 맥락에서 정확하다고 믿습니다.) cppreference.com 에 따르면 , 기계 입실론은 " 1.0
[지정된] 부동 소수점 유형으로 표현할 수있는 다음 값과의 차이 "입니다. 기계 엡실론은를 만족 1 + epsilon > 1
하지만, 그것을 만족시키는 가장 낮은 숫자 일 필요는 없습니다 . 그러나 모든 반올림 모드에서 해당 조건을 충족하는 가장 낮은 숫자입니다 .
기계 엡실론이보다 훨씬 작기 때문에 1.0
엡실론과 사이에 표현 가능한 값이 많이 0.0
있습니다. (이것이 부동 소수점 표현의 기본 목표입니다.) 이것들 중 하나가에 추가 1.0
되면 결과는 표현할 수 없으므로 결과를 반올림해야합니다. 라운딩 모드는 가장 가까운 값으로 표현할 경우, 합계로 반올림 것을 1 + epsilon
소수 사이에있을 때마다 epsilon/2
그리고 3*epsilon/2
. 반면 반올림 모드가 항상 0을 향하면 예상했던 결과를 얻을 수 있습니다.
#include <cfenv>
코드에 다음 줄을 추가해보십시오 .
fesetround(FE_TOWARDZERO);
이로 인해 1.0
와 사이의 모든 합계가 1 + epsilon
로 반올림됩니다 1.0
. 이제 예상대로 작동하는 기계 엡실론을 볼 수 있습니다.
다른 보장 된 반올림 모드는 -infinity 및 + infinity입니다. 자세한 내용은 cppreference.com 을 참조하십시오.