>

두 개의 더블이 거의 같은지 확인하기 위해 Java 코드를 찾으려고합니다. 나는 많은 인터넷 검색을 수행하고 여기에 정리 한 비트와 조각을 발견했습니다. 그것이 나를 탈출하기 시작하는 곳은 "상대 엡실론"의 사용입니다. 이 접근법은 내가 찾고있는 것처럼 보입니다. 엡실론을 직접 지정하고 싶지는 않지만 두 인수의 크기에 따라 엡실론을 사용하고 싶습니다. 다음은 내가 작성한 코드입니다. 위생 검사가 필요합니다. (PS는 위험 할 정도로 수학이 충분하다는 것을 알고 있습니다.)

public class MathUtils
{
    // http://stackoverflow.com/questions/3728246/what-should-be-the-
    // epsilon-value-when-performing-double-value-equal-comparison
    // ULP = Unit in Last Place
    public static double relativeEpsilon( double a, double b )
    {
        return Math.max( Math.ulp( a ), Math.ulp( b ) );
    }
    public static boolean nearlyEqual( double a, double b )
    {
        return nearlyEqual( a, b, relativeEpsilon( a, b ) );
    }
    // http://floating-point-gui.de/errors/comparison/
    public static boolean nearlyEqual( double a, double b, double epsilon )
    {
        final double absA = Math.abs( a );
        final double absB = Math.abs( b );
        final double diff = Math.abs( a - b );
        if( a == b )
        {
            // shortcut, handles infinities
            return true;
        }
        else if( a == 0 || b == 0 || absA + absB < Double.MIN_NORMAL )
        {
            // a or b is zero or both are extremely close to it
            // relative error is less meaningful here
            // NOT SURE HOW RELATIVE EPSILON WORKS IN THIS CASE
            return diff < ( epsilon * Double.MIN_NORMAL );
        }
        else
        {
            // use relative error
            return diff / Math.min( ( absA + absB ), Double.MAX_VALUE ) < epsilon;
        }
    }
}

  • 답변 # 1

    이 라이브러리를 사용하고 싶습니다. 일반적으로 사용하는 라이브러리는 Google Guava 라이브러리의 DoubleMath입니다. https://google.github.io/guava/releases/19.0/api/docs/com/google/common/math/DoubleMath.html

    if (DoubleMath.fuzzyEquals(a, b, epsilon)) { // a and b are equal within the tolerance given } 퍼지 비교도 있습니다.

  • 답변 # 2

    2 개의 부동 값을 비교하는 일반적인 방법 a,b  입니다 :

    if ( Math.abs(a-b) <= epsilon ) do_stuff_if_equal;
     else                       do_stuff_if_different;
    
    

    여기서 Math.abs()  절대 값입니다. Java로 코딩하지 않으므로 double 를 사용해야합니다.  그렇지 않은 경우 변형. 와이즈 비즈  당신의 차이입니다. 언급 한 epsilon  이것에 비해 너무 작습니다. 비교할 값에 적합한 값을 사용해야합니다. 그래서 ulp 를 계산하는 방법 ?

    이것은 약간 까다 롭고 네, epsilon 의 크기를 사용하는 것이 가능합니다  그러나 a,b 의 지수가  너무 다르면 쉽게 오 탐지를 얻을 수 있습니다. 대신 의미있는 값을 사용해야합니다. 예를 들어 위치 좌표를 비교하는 경우 엡실론은 동일한 점으로 간주되는 최소 디테일 또는 최소 거리의 분수 여야합니다. a,b 와 같이 충분히 작은 각의 최소 각도  그러나 값은 작업하는 범위와 정확도에 따라 다릅니다. 정규화 된 1e-6 deg  내가 보통 <-1,1> 를 사용하는 범위  또는 1e-10 .

    당신이 볼 수 있듯이 엡실론은 주로 목표 정확도와 크기에 달려 있으며 경우에 따라 매우 바뀔 수 있습니다.  당신이 원하는 것처럼) 안전하지 않으며 나중에 머리 아파로 이어질 것입니다.

    이것을 완화하기 위해 나는 보통 1e-30 를 정의한다  변경할 수있는 상수 또는 변수 (계산 클래스의 경우) 대부분의 경우에 충분한 값으로 기본값을 설정하고 어느 시점에서 문제가 발생하면 쉽게 변경할 수 있다는 것을 알고 있습니다 ...

    어쨌든 (위의 텍스트를 무시하고) 원하는 방식으로 수행하려면 다음을 수행하십시오.

    epsilon
    
    

    그러나 내가 말했듯이 이것은 잘못된 결과를 초래할 수 있습니다. _zero 를 계속 사용하는 경우  그런 다음 if (Math.abs(a)>=Math.abs(b)) epsilon=1e-30*Math.abs(b); else epsilon=1e-30*Math.abs(a); 를 사용합니다   ulp 대신 .

    Min

  • 이전 asp.net - Visual Studio 2010에서 F11 키 (디버그 모드)가 작동하지 않습니까?
  • 다음 javascript - Vuejs는 그래프에 전달할 새 배열을 만드는 방법