문제

이 코드는 작동합니다 (C# 3)

double d;
if(d == (double)(int)d) ...;
  1. 더 좋은 방법이 있습니까?
  2. 외부 이유로 나는 더블 캐스트를 피하고 싶습니다. 이 외에 어떤 좋은 방법이 있습니까? (좋지 않더라도)

메모: 몇몇 사람들은 ==가 종종 부동 소수점을 퇴보하는 (중요한) 지점을 지적했다. 이 경우 나는 0에서 수백 범위의 값을 기대하며 정수 (int가 아닌 오류)로 간주되므로 이러한 점이 "문제가되지 않으면"문제가되지 않아야합니다.

도움이 되었습니까?

해결책

d == Math.Floor(d)

다시 말해 똑같은 일을합니다.

NB : 이런 종류의 일을 할 때 매우 조심해야한다는 것을 알고 있기를 바랍니다. 플로트/복식은 명백한 이유없이 정확한 비교를 만드는 미니 스컬 오류를 매우 쉽게 축적합니다.

다른 팁

두 배가 다른 계산의 결과라면 아마도 다음과 같은 것을 원할 것입니다.

d == Math.Floor(d + 0.00001);

이렇게하면 약간의 반올림 오류가 발생하면 여전히 일치합니다.

이것은 내가 생각할 것입니다 :

if (d % 1 == 0) {
  //...
}

나는 질문의 c#-특이 적 부분에 대답 할 수 없지만, 당신은 아마도 부동 소수점 번호에 대한 일반적인 문제를 놓치고 있음을 지적해야합니다.

일반적으로 정수는 플로트에 잘 정의되어 있지 않습니다. 같은 이유로 평등이 부유물에 잘 정의되어 있지 않습니다. 부동 소수점 계산에는 일반적으로 반올림 및 표현 오류가 모두 포함됩니다.

예를 들어, 1.1 + 0.6 != 1.7.

그렇습니다. 그것은 부동 소수점 번호가 작동하는 방식입니다.

여기, 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.

엄격하게 말하면, 플로트와 함께 할 수있는 평등 비교에 가장 가까운 것은 비교하는 것입니다. 최대 선택된 정밀도.

충분하지 않은 경우, 소수점 번호 표현, 내장 오류 범위가 내장 된 부동 소수점 번호 표현 또는 상징적 계산으로 작업해야합니다.

당신이 그것을 변환하려고한다면, Mike F / Khoth의 대답은 좋지만 질문에 대답하지는 않습니다. 실제로 테스트하려고하고 실제로 중요하다면 오류의 여백이 포함 된 것을 구현하는 것이 좋습니다.

예를 들어, 돈을 고려하고 있고 달러 금액을 테스트하고 싶다면 (Khoth의 패턴에 따라) : 다음과 같이 말할 수 있습니다.

if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)

다시 말해, 값의 차이의 절대 값을 취하고 정수 표현이며 그것이 작다는 것을 확인하십시오.

거기에 여분의 (이중)가 필요하지 않습니다. 이것은 작동합니다 :

if (d == (int)d) {
 //...
}

math.truncate () 사용

'x == floor (x)'와 같은 간단한 테스트는 모든 고정 차단 FP 번호에 대해 올바르게 작동하도록 수학적으로 보장됩니다.

모든 합법적 인 고정 프리션 FP 인코딩은 뚜렷한 실수를 나타냅니다. 따라서 모든 정수 X에 대해 정확히 일치하는 고정 금지 FP 인코딩이 최대 하나 있습니다.

따라서, 그러한 방식으로 표현할 수있는 모든 정수 x에 대해, 우리는 x == 바닥 (x)이 반드시, 정의에 의해 바닥 (x)은 y <= x와 y가 정수를 나타내는 가장 큰 fp 숫자 y를 반환하기 때문에; 따라서 바닥 (x)은 x를 반환해야합니다.

이렇게하면 플로팅 포인트 드리프트를 설명하기 위해 원하는 정밀도, 플러스 또는 마이너스 반드시를 선택할 수 있습니다. 비교는 필수적입니다.

static void Main(string[] args)
{
    const int precision = 10000;

    foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
    {
        if ((int) (d*precision + .5)%precision == 0)
        {
            Console.WriteLine("{0} is an int", d);
        }
    }
}

그리고 출력은입니다

2 is an int
1.99999999 is an int
2.00000001 is an int

이 같은

double d = 4.0;
int i = 4;

bool equal = d.CompareTo(i) == 0; // true

이것을 사용할 수 있습니까?

    bool IsInt(double x)
    {
        try
        {
            int y = Int16.Parse(x.ToString());
            return true;
        }
        catch 
        {
            return false;
        }
    }

이중의 정밀도를 처리하려면 ...

Math.Abs(d - Math.Floor(d)) <= double.Epsilon

값이있는 경우 다음 경우를 고려하십시오 Double.epsilon 이하 0으로 비교하지 못합니다.

// number of possible rounds
const int rounds = 1;

// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;

// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));

// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);

// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top