numeric_limits Machine Epsilon이 1 + e> 1 조건을 충족하지 않는 이유는 무엇입니까?

Dec 24 2020

내가 틀리지 않았다면 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를 놓치고 있습니까?

답변

6 JaMiT Dec 24 2020 at 11:46

내가 틀리지 않았다면 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 을 참조하십시오.