2008-09-30 3 views
46

가 나는 doublef을 가지고 (이상 또는 이하) 여전히 원래하지만 최대한 가까운보다 확실히 더 클 수있는 새로운 가치를 아주 약간 큰 (또는 작은)를 조금씩 이동하는 방법을하고자하는 원래 .플로트를 조금씩 늘리거나 변경하는 방법?

이 가까이 아래에있을 필요가 없습니다 마지막 비트는 내가 다른 값을 생성하고 다시 원래로 반올림하지 않도록 보장 할 어떤 변화가 더 중요합니다.

+0

double 또는 float? 가지고있는 것에 따라 가장 작은 값이 달라집니다. – perimosocordiae

+0

그래, 내 질문 제목과 설명이 일치하지 않았다는 것을 알았다. 나는 답이 두 가지 경우를 다룰 수 있다고 생각했다. – Owen

답변

61

math.h 파일을 확인하십시오. 운이 좋은 경우 nextafternextafterf 함수가 정의되어 있습니다. 그들은 당신이 휴대 가능하고 플랫폼에 독립적 인 방식으로 원하는 것을 정확하게 수행하며 C99 표준의 일부입니다.

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

EDIT : 주석에서 지적한대로 이진수 표현에서 부동 소수점을 증가 시키면 충분합니다. 가수 - 오버플로는 지수를 증가시킬 것이며, 이는 우리가 원하는 것입니다.

간단히 말해서 nextafter가하는 것과 동일한 내용입니다.

그러나 완전히 이식되지는 않습니다. endianess와 모든 기계가 IEEE 플로트를 가지고있는 것은 아닙니다 (ok - 마지막 이유는 더 학문적입니다).

또한 NAN의 처리와 infinites이 까다로운 일이 될 수도있다. 단순히 숫자가 아닌 숫자로만 증분 할 수는 없습니다.

+9

오버 플로우가 원하는 지수로 넘어갈 것이므로 특별히 가수 오버플로를 처리하고 싶지는 않습니다. –

+1

쿨 - 나는 결코 그것에 대해 생각하지 않았습니다. float를 정수로 증가 시키면 필요한 것을 정확하게 수행 할 수 있습니다. –

+2

그것은 멋지다 :) 이제 누가 내 대답을 downvoted 바보가 그렇게 말하지 말아 줄래? –

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

예.

편집 : 누군가 지적했듯이, 이것은 -ve numbers, Inf, Nan 또는 overflow를 제대로 처리하지 못합니다. 위의 안전한 버전은 절대적인 측면에서

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; 
} 
+0

downvoter가 이것이 도움이되지 않는 이유에 관해서 논평 할 수 있는지 궁금합니다 ... 나 자신, nextafter() 함수를 배웠다면, 나는 이것을 선호 할 것입니다.하지만이 것이 작동한다면, 그것은 독자적으로 주목할만한 것입니다 . – Owen

+0

마이크, 실행 파일/컴파일러는 무엇입니까? –

+0

이것은 전적으로 구현에 종속적이며 이식 가능하지 않습니다. EEMMM이 있으면 제대로 작동하지만 MMMEE를 사용하면 원하는 결과를 얻을 수 없습니다. – Benoit

4

, 새로운 별개의 값이 값의 전류 크기에 따라 달라집니다하기 위해 부동 소수점 값에 추가 할 수있는 가장 작은 양이다; 형식의 machine epsilon에 현재 지수가 곱해질 것입니다. 포인트 represenation 부동의 IEEE spec 밖으로

확인합니다. 가장 간단한 방법은 값을 정수형으로 재 해석하고, 1을 더한 다음, 기호를 뒤집 지 않았거나 부호 및 지수 비트를 검사하여 NaN을 생성했는지 확인하십시오.

다른 방법으로는 현재 가수와 지수를 얻기 위해 frexp을 사용할 수 있으며, 따라서 추가 할 값을 계산합니다.

-2

이 코드는 잠시 후에 발견되었습니다. 가장 작은 코드를 결정할 때 도움이 될 것입니다.내가 똑같은 일을 할 필요가이 코드를 함께했다

#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); 
} 
3

: 그것은 가치가 무엇인지에 대한

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; 
} 
+0

좋은 점도 있습니다! –

1

, 값 불행하게도 나는이 코드에 대한 참조를 기억할 수 표준 ++ 증가 기능은 9,007199254740,992입니다.

0

이것은 정확히 원하는 것은 아니지만 여전히 numeric_limits 사용 중일 수 있습니다. 특히 min()과 엡실론() 멤버.

mydouble + numeric_limits :: 엡실론()이 mydouble이 이미 엡실론에 가깝지 않다면 원하는 것을 할 것이라고 생각하지 않습니다. 그렇다면 운이 좋다.

관련 문제