programing

C에서 캐스팅이 정수로 두 배 증가할 때 오버플로 처리

lastmoon 2023. 9. 14. 23:25
반응형

C에서 캐스팅이 정수로 두 배 증가할 때 오버플로 처리

오늘 저는 가능한 최대 정수보다 큰 두 배를 정수에 캐스팅하면 -2147483648이 나오는 것을 발견했습니다.마찬가지로 가능한 최소 정수보다 작은 두 배를 캐스팅하면 -2147483648도 나옵니다.

이 동작은 모든 플랫폼에 대해 정의되어 있습니까?
이 언더플로우/오버플로우를 감지하는 가장 좋은 방법은 무엇입니까? 것이 해결책입니까?과 maxint한을자에는이까장은에?까은장이s한f?eg는neser

캐스팅이 정수로 플로팅되면 오버플로로 인해 정의되지 않은 동작이 발생합니다.C99 규격, 섹션 6.3.1.4 실제 부동정수:

한 값을 의 과 으로 하는 이외의 _Bool). , 이 됩니다 (, 이 0 으로).정수형으로 적분 부분의 값을 나타낼 수 없으면 동작이 정의되지 않습니다.

범위를 수동으로 확인해야 하지만 다음과 같은 코드는 사용하지 마십시오.

// DON'T use code like this!
if (my_double > INT_MAX || my_double < INT_MIN)
    printf("Overflow!");

INT_MAX정확한 부동 소수점 표현이 없을있는 정수 상수입니다.플로트와 비교할 때, 가장 가까운 높은 값 또는 가장 가까운 낮은 값의 대표 부동 소수점 값으로 반올림할 수 있습니다(이 값은 구현 정의되어 있습니다).예를 들어 64비트 정수의 경우,INT_MAX이다 ㅇ2^63 - 1이다과다이로 반올림됩니다.2^63 수표는 으로, 는 으로 으로 는 가 됩니다.my_double > INT_MAX + 1. 다음과 같은 경우에는 오버플로를 감지하지 못합니다.my_double 같은2^63.

예를 들어 리눅스에서 gcc 4.9.1을 사용하면 다음과 같은 프로그램이 있습니다.

#include <math.h>
#include <stdint.h>
#include <stdio.h>

int main() {
    double  d = pow(2, 63);
    int64_t i = INT64_MAX;
    printf("%f > %lld is %s\n", d, i, d > i ? "true" : "false");
    return 0;
}

인쇄물

9223372036854775808.000000 > 9223372036854775807 is false

정수형과 이중형의 한계와 내부 표현을 미리 모른다면 이를 제대로 이해하기 어렵습니다.하지만 당신이 만약에서 전환한다면,doubleint64_t들어 한 두 배 두배로 인할 수 . 즉, 를 , 한 를 할 와 로 의 와 IEEE 로 ).

if (!(my_double >= -9223372036854775808.0   // -2^63
   && my_double <   9223372036854775808.0)  // 2^63
) {
    // Handle overflow.
}

!(A && B)또한 NaN을 올바르게 처리합니다.휴대가 가능하고 안전하지만 약간 부정확한 버전을 위한intsis:

if (!(my_double > INT_MIN && my_double < INT_MAX)) {
    // Handle overflow.
}

에서 발생하며 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ INT_MIN아니면INT_MAX이 합니다. 하지만 대부분의 응용 프로그램에서는 이 정도면 충분합니다.

limits.h유형의 터에해한과에수가다가수다한터에se에erk,esegsrrn과 주조 전에 이중 변수를 확인할 수 있습니다.

if (my_double > nextafter(INT_MAX, 0) || my_double < nextafter(INT_MIN, 0))
    printf("Overflow!");
else
    my_int = (int)my_double;

편집:nextafter()nwellnhof가 언급한 문제를 해결할 것입니다.

질문에 대답하기범위를 벗어나는 플로트를 캐스트할 때의 동작은 정의되지 않거나 구현에 특정적입니다.

경험을 바탕으로 말씀드리겠습니다.저는 MIPS64 시스템에서 이런 종류의 캐스트를 전혀 구현하지 않았습니다.CPU는 결정적인 일을 하는 대신 CPU 예외를 던졌습니다.출연진을 본받아야 할 예외 처리자가 결과에 아무런 조치를 취하지 않고 돌아왔습니다.

결국 난 임의의 정수를 가지게 되었습니다.이 원인으로 버그를 추적하는 데 얼마나 걸렸는지 맞춰보세요. :-)

번호가 유효한 범위를 벗어날 수 없는 경우 직접 범위를 확인하는 것이 좋습니다.

C++의 휴대용 방법은 Safe를 사용하는 것입니다.수업 중:

http://www.codeplex.com/SafeInt

이 구현을 통해 캐스트를 포함한 C++ 번호 유형에서 정상적인 덧셈/ 뺄셈/등을 허용할 수 있습니다.오버플로 시나리오가 감지될 때마다 예외가 발생합니다.

SafeInt<int> s1 = INT_MAX;
SafeInt<int> s2 = 42;
SafeInt<int> s3 = s1 + s2;  // throws

저는 오버플로우가 중요한 시나리오인 장소에서 이 클래스를 사용할 것을 강력히 권고합니다.그것은 묵묵히 넘쳐나는 것을 피하기 매우 어렵게 만듭니다.오버플로에 대한 복구 시나리오가 있는 경우에는 SafeIntException을 실행하고 필요에 따라 복구하기만 하면 됩니다.

SafeInt는 이제 GCC와 Visual Studio에서도 작동합니다.

이 언더플로우/오버플로우를 감지하는 가장 좋은 방법은 무엇입니까?

잘린 것 비교double가까운 곳에 제한을 두다INT_MIN,INT_MAX.

방법은 다음을 기준으로 정확하게 한계를 변환하는 입니다.INT_MIN,INT_MAX안으로double가치관. Adouble정확히 나타내지는 않을 수도 있습니다.INT_MAX비트 수로int 부동 소수점의 *1정밀도를 초과할 수도 있습니다그 경우에, 의 전환은INT_MAX로.double라운딩을 앓고 있습니다.그 다음의 수INT_MAX는 2의 power-of-2이며, 확실히 다음과 같이 나타낼 수 있습니다.double.2.0*(INT_MAX/2 + 1)1보다 큰 정수를 생성합니다.INT_MAX.

동일하게 적용.INT_MIN2s-reaction이 아닌 기계에서.

INT_MAX는 항상 2 - 1의 거듭제곱입니다.
INT_MIN는 항상:
-INT_MAX(2의 보어가 아님) 또는
-INT_MAX-1(어의

int double_to_int(double x) {
  x = trunc(x);
  if (x >= 2.0*(INT_MAX/2 + 1)) Handle_Overflow();
  #if -INT_MAX == INT_MIN
  if (x <= 2.0*(INT_MIN/2 - 1)) Handle_Underflow();
  #else

  // Fixed 2022
  // if (x < INT_MIN) Handle_Underflow();
  if (x - INT_MIN < -1.0) Handle_Underflow();

  #endif
  return (int) x;
}

하고 NaN을 하지 않는 하고 하지 trunc()

#define DBL_INT_MAXP1 (2.0*(INT_MAX/2+1)) 
#define DBL_INT_MINM1 (2.0*(INT_MIN/2-1)) 

int double_to_int(double x) {
  if (x < DBL_INT_MAXP1) {
    #if -INT_MAX == INT_MIN
    if (x > DBL_INT_MINM1) {
      return (int) x;
    }
    #else
    if (ceil(x) >= INT_MIN) {
      return (int) x;
    }
    #endif 
    Handle_Underflow();
  } else if (x > 0) {
    Handle_Overflow();
  } else {
    Handle_NaN();
  }
}

[2022 편집] 6년 만에 코너 오류 수정

double의 의 값값값(INT_MIN - 1.0 ... INT_MIN)(이 아닌) (단점으로 잘 int 이전 코드가 실패했습니다.


*1 이는 에도 적용됩니다.INT_MIN - 1int가 1/입니다.double됩니다. 는 과 됩니다 는 됩니다 과 는 는 .long long다음과 같은 다음과 같은 차이점을 생각해 보십시오.

  if (x < LLONG_MIN - 1.0) Handle_Underflow(); // Bad
  if (x - LLONG_MIN < -1.0) Handle_Underflow();// Good

로 2 으로.some_int_type_MIN π 2π (π) π a π로 됩니다.double.따라서x - LLONG_MIN관심사 범위에 있어서 정확합니다.LLONG_MIN - 1.0뺄셈에서 정밀 손실이 발생할 수 있습니다.

우리는 같은 질문을 받습니다.예를 들어:

double d = 9223372036854775807L;
int i = (int)d;

Linux/window에서는 i = -2147483648. 그러나 AIX 5.3에서는 i =2147483647.

더블이 인터거의 범위를 벗어나는 경우.

  • Linux/window는 항상 INT_MIN을 반환합니다.
  • AIX는 double이 positive이면 INT_MAX를 반환하고 double의 INT_MIN은 negative를 반환합니다.

다른 옵션은 boost::numeric_cast를 사용하여 숫자 유형 간의 임의 변환을 허용하는 것입니다.숫자 유형을 변환할 때 범위 손실을 감지하고 범위를 보존할 수 없는 경우 예외를 발생시킵니다.

위에서 참조한 웹사이트는 이 템플릿이 어떻게 사용될 수 있는지에 대한 간단한 개요를 제공하는 작은 예도 제공합니다.

물론 이것은 더이상 C가 아닙니다 ;-)

확실하지는 않지만 저는 과소/과잉에 대해 부동 소수점 예외를 "켜는" 것이 가능할 수 있다고 생각합니다.이 MSVC7\8의 부동 소수점 예외 처리를 참조하면 if/else 체크에 대한 대안이 있을 수 있습니다.

모든 플랫폼에 대해 정의되어 있는지 확실히 말할 수는 없지만, 제가 사용한 모든 플랫폼에서 일어난 일입니다.내 경험으로는 굴러가는 것 뿐입니다.즉, 배의 값이 INT_MAX + 2이면 캐스트의 결과가 INT_MIN + 2가 되는 것입니다.

최선의 방법에 관해서는, 정말 잘 모르겠습니다.저 자신도 이 문제에 부딪혔지만, 이 문제를 해결할 훌륭한 방법을 아직 찾지 못했습니다.누군가가 거기서 우리 둘 다에게 도움이 될 수 있는 응답을 할 것이라고 확신합니다.

언급URL : https://stackoverflow.com/questions/526070/handling-overflow-when-casting-doubles-to-integers-in-c

반응형