System.Double을 '0'(숫자, 정수?)과 비교하는 올바른 방법


87

죄송합니다. 어리석은 질문 일 수 있지만 확실하게 알고 있어야합니다.

if표현 이 있어요

void Foo()
{
    System.Double something = GetSomething();
    if (something == 0) //Comparison of floating point numbers with equality 
                     // operator. Possible loss of precision while rounding value
        {}
}

그 표현은

void Foo()
{
    System.Double something = GetSomething();
    if (something < 1)
        {}
}

? 그러면 문제가있을 수 있습니다. if예를 들어 0.9의 값을 사용하여 입력합니다 .


3
// Comparison of floating point numbers with equality // operator. 정말로 그것을 지정해야 했습니까? :)
George Johnston

1
젠장. 0과 1 사이에는 엄청난 양의 값이 있습니다. 테스트하고 직접 확인하는 것이 어떻습니까?
Igby Largeman 2011

12
내 초점이 어디에 있는지 보여주기 위해 Resharper와 똑같이 썼습니다.
radbyx 2011-07-06

@Charles : 또한 0보다 작은 숫자가 많이 있습니다.
Brian

답변:


115

음, 값이 0에 얼마나 가까워 야합니까? "무한 정밀도"에서 0이 될 수있는 많은 부동 소수점 연산을 수행하면 결과가 0에 "매우 가까운"결과가 될 수 있습니다.

일반적으로이 상황에서는 일종의 엡실론을 제공하고 결과가 해당 엡실론 내에 있는지 확인하려고합니다.

if (Math.Abs(something) < 0.001)

사용해야하는 엡실론은 응용 프로그램에 따라 다르며 수행중인 작업에 따라 다릅니다.

물론 결과가 정확히 0이 되어야한다면 간단한 동등성 검사가 좋습니다.


사실 정확히 0이되어야합니다. 어떻게 보일까요? Double.Zero를 찾았지만 행운을 알고 있습니다. 일정한 권리가 있습니까? BTW, 덕분에, 지금 엡실론 부분 : 수
radbyx

24
@radbyx : 그냥 == 0. 당신은 거기 그대로있어 - 꽤 상수 :)의 그
존 소총

35

경우 something이외의 작업의 결과에서 할당 된 something = 0다음보다 효율적으로 사용 :

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

편집 :이 코드는 잘못되었습니다. Epsilon은 가장 작은 숫자이지만 0은 아닙니다. 숫자를 다른 숫자와 비교하려면 허용 가능한 허용 오차가 무엇인지 생각해야합니다. .00001 이상은 신경 쓰지 않는다고 가정 해 봅시다. 그것은 당신이 사용할 숫자입니다. 값은 도메인에 따라 다릅니다. 그러나 대부분 Double.Epsilon은 아닙니다.


2
이것은 예를 들어, 반올림 문제가 해결되지 Math.Abs(0.1f - 0.1d) < double.Epsilon이다false
토마스 Lulé

6
Double.Epsilon은 그러한 비교에 너무 작습니다. Double.Epsilon은 double이 나타낼 수있는 가장 작은 양수입니다.
Evgeni Nabokov

3
이것은 0과 비교하는 것과 거의 동일하기 때문에 의미가 없습니다. -1
Gaspa79

1
목표는 ==를 사용하지 않고 0 개념과 비교하는 것입니다. 적어도 수학적으로 감각을 만듭니다. 나는 당신이 손에 이중을 가지고 있다고 가정하고 그것을 ==없이 0의 개념과 비교하고 싶습니다. 반올림을 포함하여 어떤 이유로 든 double이 0d와 다른 경우 테스트 채우기는 false를 반환합니다. 이 비교는 모든 double에 대해 유효 해 보이며이 double이 표현할 수있는 가장 작은 숫자보다 작은 경우에만 true를 반환합니다. 이는 0, no?의 개념을 테스트하는 데 좋은 정의로 보입니다.
sonatique

3
@MaurGi : 당신이 틀렸어요 : double d = Math.Sqrt(10100)*2; double a = Math.Sqrt(40400); if(Math.Abs(a - d) < double.Epsilon) { Console.WriteLine("true"); }
sonatique

26

귀하 something는이며 double라인에서 올바르게 식별했습니다.

if (something == 0)

우리는 double왼쪽에 (lhs)와 int오른쪽에 (rhs)가 있습니다.

당신이 LHS가 변환됩니다 생각처럼하지만 지금은 것 int, 다음 ==기호는 두 개의 정수를 비교합니다. 그것은 일어나는 일 이 아닙니다 . 변환 에서 double 에가 int 있다 명시 하고 "자동으로"일어날 수 없습니다.

대신 그 반대가 발생합니다. 우변은로 변환되고 double, 다음 ==기호는 두 배로 사이의 평등을 테스트하게된다. 이 변환은 암시 적 (자동)입니다.

글을 쓰는 것이 (일부는) 더 나은 것으로 간주됩니다.

if (something == 0.0)

또는

if (something == 0d)

두 개의 복식을 비교하는 것이 즉각적이기 때문입니다. 그러나 컴파일러는 어떤 경우에도 동일한 작업을 수행하므로 스타일과 가독성의 문제 일뿐입니다.

경우에 따라 Jon Skeet의 답변에서와 같이 "관용"을 도입하는 것도 관련이 있지만 그 관용 double도 마찬가지입니다. 이 의 과정이 될 1.0당신이 원하는 경우에, 그러나 그것은으로 [가장 엄격하게 긍정적 인] 정수가 없습니다.


17

단순히 경고를 표시하지 않으려면 다음을 수행하십시오.

if (something.Equals(0.0))

물론 이것은 드리프트가 문제가되지 않는다는 것을 알고있는 경우에만 유효한 솔루션입니다. 나는 종종 0으로 나누려고하는지 확인하기 위해 이것을한다.


4

솔직히 평등하다고 생각하지 않습니다. 자신의 예를 고려하십시오 : something = 0.9 또는 0.0004. 첫 번째 경우에는 FALSE이고 두 번째 경우에는 TRUE입니다. 이 유형을 다루면서 나는 일반적으로 정밀도 비율을 정의하고 그 정밀도 내에서 비교합니다. 귀하의 필요에 따라 다릅니다. 뭔가 ...

if(((int)(something*100)) == 0) {


//do something
}

도움이 되었기를 바랍니다.


2
정확히 0이어야합니다.
radbyx 2011

당신이 그렇게 :이 경우에있어 행운의 사나이,
티그

3

다음은 문제를 보여주는 예제입니다 (LinQPad에서 준비 됨-없는 경우 방법 Console.Writeline대신 사용 Dump) :

void Main()
{
    double x = 0.000001 / 0.1;
    double y = 0.001 * 0.01; 

    double res = (x-y);
    res.Dump();
    (res == 0).Dump();
}

x와 y는 모두 이론적으로 동일하고 0.00001과 같습니다. 그러나 "무한 정밀도"가 없기 때문에 이러한 값은 약간 다릅니다. 안타깝게도 false일반적인 방법으로 0과 비교할 때 약간만 반환 됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.