programing

휴대용 isnan/isinf 기능을 만드는 방법

powerit 2023. 10. 30. 21:18
반응형

휴대용 isnan/isinf 기능을 만드는 방법

사용해왔습니다.isinf,isnan완벽하게 작동했던 리눅스 플랫폼의 기능들.하지만 이것이 OS-X에서 작동하지 않아서 사용하기로 결정했습니다.std::isinf std::isnan리눅스와 OS-X 둘 다에서 작동합니다.

하지만 인텔 컴파일러는 그것을 인식하지 못하고, http://software.intel.com/en-us/forums/showthread.php?t=64188 에 따르면 인텔 컴파일러의 버그인 것 같습니다.

그래서 이제 저는 번거롭지 않고 제 자신의 것을 정의하고자 합니다.isinf,isnan실행.

이것이 어떻게 이루어질 수 있는지 아는 사람?

편집:

이것을 내 소스코드로 만들어 버렸습니다.isinf/isnan일해

#include <iostream>
#include <cmath>

#ifdef __INTEL_COMPILER
#include <mathimf.h>
#endif

int isnan_local(double x) { 
#ifdef __INTEL_COMPILER
  return isnan(x);
#else
  return std::isnan(x);
#endif
}

int isinf_local(double x) { 
#ifdef __INTEL_COMPILER
  return isinf(x);
#else
  return std::isinf(x);
#endif
}


int myChk(double a){
  std::cerr<<"val is: "<<a <<"\t";
  if(isnan_local(a))
    std::cerr<<"program says isnan";
  if(isinf_local(a))
    std::cerr<<"program says isinf";
  std::cerr<<"\n";
  return 0;
}

int main(){
  double a = 0;
  myChk(a);
  myChk(log(a));
  myChk(-log(a));
  myChk(0/log(a));
  myChk(log(a)/log(a));

  return 0;
}

이 작업에 부스트를 사용할 수도 있습니다.

#include <boost/math/special_functions/fpclassify.hpp> // isnan

if( boost::math::isnan( ... ) .... )

나는 이것을 시도해 본 적은 없지만, 나는 생각할 것입니다.

int isnan(double x) { return x != x; }
int isinf(double x) { return !isnan(x) && isnan(x - x); }

효과가 있을 겁니다.더 좋은 방법이 있어야 할 것 같지만, 효과가 있을 겁니다.

에 따르면 무한대는 쉽게 확인할 수 있습니다.

  • 부호 = 양/음의 무한을 나타내는 0 또는 1비트입니다.
  • 지수 = 모든 1비트.
  • tantissa = 모두 0비트입니다.

NaN은 고유한 표현이 없기 때문에 조금 더 복잡합니다.

  • 부호 = 0 또는 1.
  • 지수 = 모든 1비트.
  • tantissa = 모든 0비트를 제외한 모든 것(모든 0비트는 무한대를 나타냅니다.

아래는 이중 정밀 부동 소수점 케이스 코드입니다.단일 정밀도도 마찬가지로 쓸 수 있습니다(복수의 경우 지수가 11비트, 단식의 경우 8비트임을 기억하십시오).

int isinf(double x)
{
    union { uint64 u; double f; } ieee754;
    ieee754.f = x;
    return ( (unsigned)(ieee754.u >> 32) & 0x7fffffff ) == 0x7ff00000 &&
           ( (unsigned)ieee754.u == 0 );
}

int isnan(double x)
{
    union { uint64 u; double f; } ieee754;
    ieee754.f = x;
    return ( (unsigned)(ieee754.u >> 32) & 0x7fffffff ) +
           ( (unsigned)ieee754.u != 0 ) > 0x7ff00000;
}

구현은 매우 간단합니다(OpenCV 헤더 파일에서 가져온 것입니다).올바르게 선언해야 할 동일한 크기의 부호 없는 64비트 정수에 대한 결합을 사용합니다.

#if defined _MSC_VER
  typedef unsigned __int64 uint64;
#else
  typedef uint64_t uint64;
#endif

Visual Studio 2008에서 작동합니다.

#include <math.h>
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#define fpu_error(x) (isinf(x) || isnan(x))

안전을 위해서 fpu_error()를 사용하는 것을 추천합니다.어떤 숫자들은 isan()으로, 어떤 숫자들은 isinf()로, 그리고 어떤 숫자들은 isinf()로, 그리고 당신은 둘 다 안전해야 한다고 생각합니다.

테스트 코드는 다음과 같습니다.

double zero=0;
double infinite=1/zero;
double proper_number=4;
printf("isinf(infinite)=%d.\n",isinf(infinite));
printf("isinf(proper_number)=%d.\n",isinf(proper_number));
printf("isnan(infinite)=%d.\n",isnan(infinite));
printf("isnan(proper_number)=%d.\n",isnan(proper_number));

double num=-4;
double neg_square_root=sqrt(num);
printf("isinf(neg_square_root)=%d.\n",isinf(neg_square_root));
printf("isinf(proper_number)=%d.\n",isinf(proper_number));
printf("isnan(neg_square_root)=%d.\n",isnan(neg_square_root));
printf("isnan(proper_number)=%d.\n",isnan(proper_number));

출력은 다음과 같습니다.

isinf(infinite)=1.
isinf(proper_number)=0.
isnan(infinite)=0.
isnan(proper_number)=0.
isinf(neg_square_root)=1.
isinf(proper_number)=0.
isnan(neg_square_root)=1.
isnan(proper_number)=0.

isnan는 현재 C++11의 일부이며, GCC++에 포함되어 있다고 생각하며, Apple LLVM.

이제 MSVC++기능이 있습니다.

적절한.#define모래를#includes는 적절한 해결책을 만들어야 합니다.

하지만 저는 nan detection 대신 nan이 발생하지 않도록 하는 것을 추천합니다.

인텔이 버그를 수정하거나 해결 방법을 제공할 때까지 기다리는 것이 이상적입니다 :-)

하지만 만약 당신이 탐지하고 싶다면NaN그리고.InfIEEE754 값에서 정수(단일 정밀도인지 이중 정밀도인지에 따라 32비트 또는 64비트)로 매핑하고 지수 비트가 모두 1인지 확인합니다.이것은 그 두 경우를 나타냅니다.

당신은 구별할 수 있습니다.NaN그리고.Inf가수의 높은 차수의 비트를 확인함으로써.면 입니다.NaN그렇지않으면Inf.

+/-Inf부호 비트에 의해 지시됩니다.

단일 정밀도(32비트 값)의 경우 부호는 상위 비트(b31), 지수는 다음 8비트(+23비트 가수)입니다.두 배의 정밀도를 위해 부호는 여전히 높은 차수의 비트이지만 지수는 11비트(가수의 경우 52비트 포함)입니다.

위키피디아는 모든 끔찍한 세부사항들을 가지고 있습니다.

다음 코드는 인코딩의 작동 방식을 보여줍니다.

#include <stdio.h>

static void decode (char *s, double x) {
    long y = *(((long*)(&x))+1);

    printf("%08x ",y);
    if ((y & 0x7ff80000L) == 0x7ff80000L) {
        printf ("NaN  (%s)\n", s);
        return;
    }
    if ((y & 0xfff10000L) == 0x7ff00000L) {
        printf ("+Inf (%s)\n", s);
        return;
    }
    if ((y & 0xfff10000L) == 0xfff00000L) {
        printf ("-Inf (%s)\n", s);
        return;
    }
    printf ("%e (%s)\n", x, s);
}

int main (int argc, char *argv[]) {
    double dvar;

    printf ("sizeof double = %d\n", sizeof(double));
    printf ("sizeof long   = %d\n", sizeof(long));

    dvar = 1.79e308; dvar = dvar * 10000;
    decode ("too big", dvar);

    dvar = -1.79e308; dvar = dvar * 10000;
    decode ("too big and negative", dvar);

    dvar = -1.0; dvar = sqrt(dvar);
    decode ("imaginary", dvar);

    dvar = -1.79e308;
    decode ("normal", dvar);

    return 0;
}

출력:

sizeof double = 8
sizeof long   = 4
7ff00000 +Inf (too big)
fff00000 -Inf (too big and negative)
fff80000 NaN  (imaginary)
ffefdcf1 -1.790000e+308 (normal)

이 코드(방법은 아님)는 휴대성이 지나치게 높지 않은 긴 길이의 크기에 크게 의존한다는 것을 명심하십시오.하지만 정보를 얻기 위해 약간의 조작을 해야 한다면 이미 그 영역에 진입한 것입니다 :-)

덧붙여서, 저는 항상 Harald Schmidt의 IEEE754 변환기가 부동 소수점 분석에 매우 유용하다고 생각했습니다.

아주 간단한 IEEE 754-1985 호환 코드를 사용하면 됩니다.

static inline bool  ISINFINITE( float a )           { return (((U32&) a) & 0x7FFFFFFFU) == 0x7F800000U; }
static inline bool  ISINFINITEPOSITIVE( float a )   { return (((U32&) a) & 0xFFFFFFFFU) == 0x7F800000U; }
static inline bool  ISINFINITENEGATIVE( float a )   { return (((U32&) a) & 0xFFFFFFFFU) == 0xFF800000U; }
static inline bool  ISNAN( float a )                { return !ISINFINITE( a ) && (((U32&) a) & 0x7F800000U) == 0x7F800000U; }
static inline bool  ISVALID( float a )              { return (((U32&) a) & 0x7F800000U) != 0x7F800000U; }

Boost가 이 기능을 제공한다고 Brubelsabs가 말했듯이, 여기 보고된 바와 같이, 사용하는 대신

if (boost::math::isnan(number))

이를 사용해야 합니다.

if ((boost::math::isnan)(number))

다음을 반환하는 C99 함수 fpclassify에 대해서는 아무도 언급하지 않은 것 같습니다.

FP_INFINITE, FP_NAN, FP_NORMAL, FP_SUBNORMAL, FP_ZERO 또는 구현 정의형 중 하나로 arg의 범주를 지정합니다.

이것은 비주얼 스튜디오에서 작동하지만 OS-X에 대해서는 잘 모릅니다.

다음 기사는 isnan에 대한 몇 가지 흥미로운 트릭을 가지고 있으며 inf: http://jacksondunstan.com/articles/983

이것은 osx에서 작동합니다.

#include <math.h>

휴대용일 수도 있고요

int isinf( double x ) { return x == x - 1; }

편집:

크리스가 지적했듯이 위의 것들은 큰 x로 실패할지도 모릅니다.

int isinf( double x ) { return x == x * 2; }

언급URL : https://stackoverflow.com/questions/2249110/how-do-i-make-a-portable-isnan-isinf-function

반응형