가장 작은 증분 (또는 그에 가깝게)으로 플로트를 변경하는 방법?

StackOverflow https://stackoverflow.com/questions/155378

  •  03-07-2019
  •  | 
  •  

문제

나는있다 doublef 그리고 원본에 최대한 가깝지만 원본보다 엄격하게 더 큰 새로운 값을 얻기 위해 매우 크게 (또는 작은) 새 가치를 얻는 방법을 원합니다.

마지막 비트에 가까울 필요는 없습니다. 제가 변경하는 모든 것이 다른 값을 생성하고 원본으로 돌아 가지 않도록 보장하는 것이 더 중요합니다.

도움이 되었습니까?

해결책

Math.h 파일을 확인하십시오. 운이 좋으면 nextafter 그리고 nextafterf 정의 된 기능. 그들은 휴대용 및 플랫폼 독립적 인 방식으로 원하는 것을 정확하게 수행하며 C99 표준의 일부입니다.

이를 수행하는 또 다른 방법 (폴백 솔루션이 될 수 있음)은 플로트를 Mantissa와 지수 부분으로 분해하는 것입니다. 증분은 쉽습니다. Mantissa에 하나를 추가하십시오. 오버플로가 발생하면 지수를 증가 시켜이 작업을 처리해야합니다. 감소는 같은 방식으로 작동합니다.

편집하다: 주석에서 지적했듯이 이진 표현에서 플로트를 증가시키는 것으로 충분합니다. Mantissa-Overflow는 지수를 증가시킬 것이며 이것이 바로 우리가 원하는 것입니다.

그것은 NextAfter가하는 것과 똑같은 일입니다.

이것은 완전히 휴대용이 아닙니다. 당신은 endianess를 다루어야하며 모든 기계에 IEEE 플로트가있는 것은 아니라는 사실을 다루어야합니다 (OK- 마지막 이유는 더 학문적입니다).

또한 Nan과 Infinites를 처리하는 것은 약간 까다로울 수 있습니다. 숫자가 아닌 정의에 따라 단순히 증가시킬 수는 없습니다.

다른 팁

u64 &x = *(u64*)(&f);
x++;

예, 진지하게.

편집하다: 누군가가 지적했듯이, 이것은 -Ve 숫자, INF, NAN 또는 오버플로를 제대로 다루지 않습니다. 위의 더 안전한 버전은입니다

u64 &x = *(u64*)(&f);
if( ((x>>52) & 2047) != 2047 )    //if exponent is all 1's then f is a nan or inf.
{
    x += f>0 ? 1 : -1;
}

절대적인 용어로, 새로운 별개의 값을 만들기 위해 부동 소수점 값에 추가 할 수있는 가장 작은 양은 값의 현재 크기에 따라 다릅니다. 유형이 될 것입니다 기계 엡실론 현재 지수를 곱합니다.

확인하십시오 IEEE 사양 부동 소수점 표현. 가장 간단한 방법은 정수 유형으로 값을 재 해석하는 것입니다. 1을 추가 한 다음 부호와 지수 비트를 검사하여 부호를 뒤집지 않았거나 NAN을 생성하지 않았는지 확인하십시오.

또는 사용할 수 있습니다 프록스 현재 Mantissa와 지수를 얻으려면 추가 할 값을 계산합니다.

나는 똑같은 일을해야 했고이 코드를 생각해 냈습니다.

double DoubleIncrement(double value)
{
  int exponent;
  double mantissa = frexp(value, &exponent);
  if(mantissa == 0)
    return DBL_MIN;

  mantissa += DBL_EPSILON/2.0f;
  value = ldexp(mantissa, exponent);
  return value;
}

가치가있는 것에 대해, 표준 ++ 증분 기능이 중단되는 가치는 9,007,199,254,740,992입니다.

이것은 정확히 당신이 원하는 것이 아닐 수도 있지만 여전히 찾을 수 있습니다. Numeric_Limits 사용 중. 특히 멤버 Min () 및 Epsilon ().

MyDouble이 이미 Epsilon에 가까워지지 않는 한 MyDouble + Numeric_limits :: Epsilon ()과 같은 것이 당신이 원하는 것을 할 것이라고 생각하지 않습니다. 그렇다면 운이 좋다.

나는이 코드를 잠시 전에 발견했다. 아마도 그것은 당신이 그것을 푸시 할 수있는 가장 작은 것을 결정하는 데 도움이 될 것이다. 불행히도 나는이 코드에 대한 참조를 기억할 수 없습니다.

#include <stdio.h>

int main()
{
    /* two numbers to work with */
    double number1, number2;    // result of calculation
    double result;
    int counter;        // loop counter and accuracy check

    number1 = 1.0;
    number2 = 1.0;
    counter = 0;

    while (number1 + number2 != number1) {
        ++counter;
        number2 = number2 / 10;
    }
    printf("%2d digits accuracy in calculations\n", counter);

    number2 = 1.0;
    counter = 0;

    while (1) {
        result = number1 + number2;
        if (result == number1)
            break;
        ++counter;
        number2 = number2 / 10.0;
    }

    printf("%2d digits accuracy in storage\n", counter );

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