IEEE_IS_FINITE(), IEEE_IS_NAN() by 바죠

컴퓨터 계산을 하다보면 정말 예기치 않은 상황을 맞이할 때가 있다.
그 중 하나가 바로 NaN이라는 것이다. 해당 변수를 출력하면 이렇게 나타난다. 이것은 Not-a-Number를 표현한다. 해당 변수가 더이상 숫자가 아니라는 것이다. 프로그램에서 무엇인가를 잘못해서 변수가 숫자가 되어야 하는데 변수가 숫자가 아닌것이 된 것이다.
예를 들어 0.0으로 다른 숫자를 나누려고한 경우나, -1.0에 대한 제곱근을 구하려고한 경우가 바로 NaN에 해당된다. 즉, 컴퓨터는 해당 계산을 수행한 다음 NaN을 변수에 주게된다.

프로그램에서 이러한 경우가 발생하지 않도록 사전에 조치를 취해야만 할 것이다.
하지만, 우선 발견을 해야 조치를 취할 수 있는 법이다. 물론 원인을 파악할 수 있으면 조치는 매우 간단하게 될수있다.
대부분 원인을 찾으면 처방은 의외로 간단하다.  
그래서 우선 찾아내는 방법이 필요하다.
https://en.wikipedia.org/wiki/NaN





http://fortranwiki.org/fortran/show/ieee_arithmetic

http://www.ibm.com/support/knowledgecenter/SS2MB5_14.1.0/com.ibm.xlf141.bg.doc/language_ref/isnan.html
https://software.intel.com/en-us/node/692942



Elemental Module Intrinsic Function (Generic): Returns whether an IEEE value is Not-a-Number (NaN).


Module

USE, INTRINSIC :: IEEE_ARITHMETIC


Syntax

result = IEEE_IS_NAN (x)


x
 
(Input) Must be of type REAL.


Results

The result type is default logical. The result has the value true if the value of x is NaN; otherwise, false.



!234567890
       USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY : IEEE_IS_FINITE,IEEE_IS_NAN
       implicit none
       integer i
       real*8 tmp,tmq,tmr

       call random_seed()

       call random_number(tmp)
       i=tmp*10+1
       tmp=exp(1000.**53)/exp(1000.**53)
       if(isnan(tmp))then
       write(6,*) tmp,' isnan'
                     endif
       write(6,*)
       if(ieee_is_nan(tmp))then
       write(6,*) tmp,' ieee_is_nan'
                           endif
       write(6,*)
       tmp=1./0.
       if(.not. IEEE_IS_FINITE(tmp))then
       write(6,*) tmp, 'is not finite'
                                    endif
       write(6,*)
       do i=1,10
       call random_number(tmp)
       write(6,*) tmp
       enddo

       stop
       end

------------------------------------------------------------------------------------------------------------------
!234567890
       subroutine tonormal(xxx)
       USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY : IEEE_IS_FINITE,IEEE_IS_NAN
       implicit none
       real*8 xxx
       real ranmar

       if(isnan(xxx)) xxx=ranmar()
       if(IEEE_IS_NAN(xxx)) xxx=ranmar()
       if(.not. IEEE_IS_FINITE(xxx)) xxx=ranmar()
       end subroutine tonormal
------------------------------------------------------------------------------------------------------------------



 NaN                      isnan
 
 NaN                      ieee_is_nan
 
 Infinity                is not finite
 
  0.613091965258501    
  0.579116799042060    
  0.430375181409478    
  0.310413425967628    
  0.960177203926751    
  0.910488043628391    
  0.247542977352232    
  9.715453361074204E-002
  0.710741738981122    
  0.838028752353247    




------------------------------------------------------------------------------------------------------------------
!234567890
       USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY : IEEE_IS_FINITE,IEEE_IS_NAN
       implicit none
       integer i
       real*8 tmp,tmq,tmr

       call random_seed()

       call random_number(tmp)
       i=tmp*10+1
       tmq=exp(1000.**53)/exp(1000.**53)
       if(isnan(tmq))then
       write(6,*) tmq,' isnan'
       call tonormal(tmq)
       write(6,*) tmq,'after'
                     endif
       write(6,*)
       tmp=exp(1000.**53)/exp(1000.**53)
       if(ieee_is_nan(tmp))then
       write(6,*) tmp,' ieee_is_nan'
       call tonormal(tmp)
       write(6,*) tmp,'after'
                           endif
       write(6,*)
       tmp= 1./0.
       if(.not. IEEE_IS_FINITE(tmp))then
       write(6,*) tmp, 'is not finite'
       call tonormal(tmp)
       write(6,*) tmp,'after'
                                    endif
       write(6,*)
       tmp=-1./0.
       if(.not. IEEE_IS_FINITE(tmp))then
       write(6,*) tmp, 'is not finite'
       call tonormal(tmp)
       write(6,*) tmp,'after'
                                    endif
       write(6,*)
       do i=1,10
       call random_number(tmp)
       write(6,*) tmp
       enddo

       stop
       end
!234567890
       subroutine tonormal(xxx)
       USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY : IEEE_IS_FINITE,IEEE_IS_NAN
       implicit none
       real*8 xxx
       real*8 tmp
!      real ranmar

       call random_number(tmp)
       if(isnan(xxx)) xxx=tmp
       call random_number(tmp)
       if(IEEE_IS_NAN(xxx)) xxx=tmp
       call random_number(tmp)
       if(.not. IEEE_IS_FINITE(xxx)) xxx=tmp
       end subroutine tonorma

 ./a.out
 NaN                      isnan
  0.493219157179643      after
 
 NaN                      ieee_is_nan
  0.118539605325025      after
 
 Infinity                is not finite
  0.500495532314348      after
 
 -Infinity               is not finite
  0.569107576913266      after
 
  9.011590371832784E-002
  6.196648220864624E-002
  3.774360064799240E-002
  0.635909791594525    
  0.907416096017866    
  0.868245692365281    
  0.995646819300007    
  0.985228747941758    
  0.633871650266967    
  0.731964336343559    


Infinity, -Infinity, NaN 모두 인수로 전달이 가능하다.

------------------------------------------------------------------------------------------------------------------
https://www.ibm.com/support/knowledgecenter/SS2MB5_14.1.0/com.ibm.xlf141.bg.doc/language_ref/isnan.html

USE, INTRINSIC :: IEEE_ARITHMETIC
REAL :: X = -1.0
IF (IEEE_SUPPORT_DATATYPE(X)) THEN
  IF (IEEE_SUPPORT_SQRT(X)) THEN    ! IEEE-compliant SQRT function
    IF (IEEE_SUPPORT_NAN(X)) THEN
      PRINT *, IEEE_IS_NAN(SQRT(X)) ! Prints true
    ENDIF
  ENDIF
ENDIF

USE, INTRINSIC :: IEEE_ARITHMETIC
REAL :: X = -1.0
IF (IEEE_SUPPORT_STANDARD(X)) THEN
  PRINT *, IEEE_IS_NAN(SQRT(X))     ! Prints true
ENDIF

------------------------------------------------------------------------------------------------------------------
http://en.cppreference.com/w/cpp/numeric/math/isnan


------------------------------------------------------------------------------------------------------------------
http://incredible.egloos.com/4786138
http://incredible.egloos.com/4811847


ifort  -CB -check all -warn interface -assume realloc_lhs   aaa.f90

pgf90

g Options
              -C -g -gopt -M[no]bounds -Mchkfpstk -Mchkptr -Mchkstk -Mcoff -Mdwarf1 -Mdwarf2 -Mdwarf3 -Melf -Mnodwarf -M[no]pgicoff -[no]traceback


------------------------------------------------------------------------------------------------------------------
program  rosetta_divbyzero
   implicit none
   integer, parameter :: rdp = kind(1.d0)
   real(rdp) :: normal,zero
 
   normal = 1.d0
   zero = 0.d0
 
   call div_by_zero_check(normal,zero)
 
contains
 
   subroutine  div_by_zero_check(x,y)
      use, intrinsic  :: ieee_exceptions
      use, intrinsic  :: ieee_arithmetic
      implicit none
      real(rdp), intent(in) :: x,y
 
      real(rdp) :: check
      type(ieee_status_type) :: status_value
      logical :: flag

      flag = .false.
      ! Get the flags
      call ieee_get_status(status_value)
      ! Set the flags quiet
      call ieee_set_flag(ieee_divide_by_zero,.false.)
      write(*,*)"Inf supported? ",ieee_support_inf(check)
 
      ! Calculation involving exception handling
      check = x/y
      write(*,*)"Is check finite?",ieee_is_finite(check), check
 
      call ieee_get_flag(ieee_divide_by_zero, flag)
      if (flag) write(*,*)"Warning! Division by zero detected"
 
      ! Restore the flags
      call ieee_set_status(status_value)
 
   end subroutine div_by_zero_check
 
end program rosetta_divbyzero
http://rosettacode.org/wiki/Detect_division_by_zero#Fortran

------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------


핑백

덧글

  • 채널 2nd™ 2017/02/06 23:58 # 답글

    'not-a-Number' 말고, 예컨대, 'not-a-Char' 이런 것도 정의 되어 있나요? (문자열 처리할 때 EOF 같은..)
  • 바죠 2017/02/07 09:07 # 삭제

    말씀하신, not-a-Char라는 것은 없는것 같습니다.



    90 continue
    read (*, *, err=90) number

    program test
    integer var,iostat,ios
    10 read(*,*,iostat=ios) var
    if (ios.ne.0) then
    write(*,*)'You've entered an incorrect value. Try again'
    goto 10
    endif
    end
    program read_val
    integer value
    character(len=10) string, string2
    string = '154'

    ! Convert a string to a numeric value
    read (string,'(I10)') value
    print *, value

    ! Convert a value to a formatted string
    write (string2,'(I10)') value
    print *, string2
    end program read_val
  • 바죠 2018/11/21 16:06 # 삭제 답글

    http://fortranwiki.org/fortran/show/ieee_arithmetic

    gfortran 5.0 버전 이후 부터 ieee_arithmetic 지원함.
댓글 입력 영역

최근 포토로그



MathJax