문제

C89에서 Floor()는 double을 반환합니다.다음은 작동이 보장됩니까?

double d = floor(3.0 + 0.5);
int x = (int) d;
assert(x == 3);

제가 걱정하는 점은 Floor 결과가 IEEE 754에서 정확하게 표현되지 않을 수 있다는 것입니다.따라서 d는 2.99999와 같은 값을 얻고 x는 결국 2가 됩니다.

이 질문에 대한 대답이 '예'가 되려면 int 범위 내의 모든 정수가 double로 정확히 표현 가능해야 하며, Floor는 항상 정확하게 표현된 값을 반환해야 합니다.

도움이 되었습니까?

해결책

부동 소수점 유형이 필요한 만티사 비트를 지원하는 경우 모든 정수는 정확한 부동 소수점 표현을 가질 수 있습니다. 부터 double Mantissa에는 53 비트를 사용하여 32 비트를 모두 저장할 수 있습니다. int정확히. 결국, 당신은 값을 지수가 0 인 Mantissa로 설정할 수 있습니다.

다른 팁

Floor ()의 결과가 정확히 표현되지 않으면 D의 값은 무엇을 기대합니까? 확실히 당신이 갖다 변수에서 부동 소수점 번호의 표현은 정의상 정확히 표현할 수 없습니까? 당신은 갖다 D의 표현 ...

(또한 Mehrdad의 답변은 32 비트 int에 맞습니다. 64 비트 더블이있는 컴파일러에서 그리고 64 비트 int, 물론 더 많은 문제가 있습니다 ...)

편집 : 아마도 당신은 "floor ()의 이론적 결과, 즉 인수보다 작거나 같은 가장 큰 정수 값은 int로 표현되지 않을 수 있습니다"를 의미합니다. 그것은 확실히 사실입니다. int가 32 비트 인 시스템에 대해 간단한 방법을 보여주는 간단한 방법 :

int max = 0x7fffffff;
double number = max;
number += 10.0;
double f = floor(number);
int oops = (int) f;

플로팅 포인트에서 정수 오버플로로 변환 할 때 C가 무엇을하는지 기억할 수 없지만 여기서 일어날 것입니다.

편집 : 고려해야 할 다른 흥미로운 상황도 있습니다. 여기에 몇 가지 C# 코드와 결과가 있습니다. 적어도 상상할 것입니다. 비슷한 C#, C#, C#, double 64 비트로 정의됩니다 long.

using System;
class Test
{
    static void Main()
    {
        FloorSameInteger(long.MaxValue/2);
        FloorSameInteger(long.MaxValue-2);
    }

    static void FloorSameInteger(long original)
    {
        double convertedToDouble = original;
        double flooredToDouble = Math.Floor(convertedToDouble);
        long flooredToLong = (long) flooredToDouble;

        Console.WriteLine("Original value: {0}", original);
        Console.WriteLine("Converted to double: {0}", convertedToDouble);
        Console.WriteLine("Floored (as double): {0}", flooredToDouble);
        Console.WriteLine("Converted back to long: {0}", flooredToLong);
        Console.WriteLine();
    }
}

결과:

원래 가치 : 4611686018427387903
이중으로 변환 : 4.61168601842739E+18
바닥 (이중으로) : 4.61168601842739E+18
Long으로 다시 변환 : 4611686018427387904

원래 가치 : 9223372036854775805
이중으로 변환 : 9.22237203685478E+18
바닥 (이중으로) : 9.22337203685478E+18
Long으로 다시 변환 : -9223372036854775808

다시 말해:

(long) floor((double) original)

항상 동일하지는 않습니다 original. 이것은 놀랍지 않아야합니다. 두 배보다 긴 값이 더 길고 (NAN 값이 주어지면) 많은 복식이 정수가 아니므로 오랫동안 오랫동안 표현할 수있을 것으로 기대할 수는 없습니다. 그러나 32 비트 정수 ~이다 복식으로 표현할 수 있습니다.

질문하고 싶은 내용이 다소 혼란스러우신 것 같습니다. floor(3 + 0.5) 3, 0.5 및 그 합은 모두 실제 부동 소수점 형식으로 정확하게 표현할 수 있기 때문에 좋은 예는 아닙니다. floor(0.1 + 0.9) 더 나은 예가 될 것이며 여기서 실제 질문은 결과가 floor 정확하게 표현 가능하지만 숫자가 부정확한지 여부 앞서서 부름 floor 모든 숫자가 정확했다면 예상한 것과 다른 반환 값이 반환됩니다.이 경우 대답은 '예'라고 생각합니다. 하지만 이는 특정 숫자에 따라 많이 달라집니다.

이 접근 방식이 나쁘다면 다른 사람들에게 비판을 권유하지만 가능한 해결 방법 중 하나는 숫자를 곱하는 것입니다. (1.0+0x1p-52) 또는 전화하기 전에 비슷한 것 floor (아마도 nextafter 더 좋을 것입니다).이는 숫자의 마지막 이진 자리의 오류로 인해 숫자가 정확히 정수 값이 아닌 바로 아래로 떨어지는 경우를 보상할 수 있지만 여러 작업을 통해 누적된 오류는 설명하지 않습니다.해당 수준의 숫자 안정성/정확성이 필요한 경우 심층 분석을 수행하거나 숫자를 올바르게 처리할 수 있는 임의 정밀도 또는 정확한 수학 라이브러리를 사용해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top