C++Guns – RoboBlog

31.05.2017

FORTRAN - NaN and min() max()

Filed under: Allgemein — Tags: — Thomas @ 19:05

What happens if one put NaN into min() or max()? Will it return NaN or the other number? Is it deterministic or random?
Sounds easy to test but its hard to implement. For example: How one get a quite-NaN number? A quite-NaN dosen't trigger debug traps, signaling-NaN do. There is no standard way in pre Fortran 2003! One have to google some nasty integer-float bit tricks. But with Fortran 2003 there is an intrinsic module ieee_arithmetic, which has the function ieee_value() which can return a quite-NaN. And one can test for Nan wich the function ieee_is_nan().

Remeber, C++ provide this functionality with std::numeric_limits::quite_nan() in C++1998 or earlier.

So the test ist quite simple. We put a number and NaN into min() and compare the result with our expected number. We do this for every combination and for min() and max(). The result for gfortran 6.3.2 32bit is: The returned number is alway not NaN, expect for the case where both parameter are NaN. Then, the function has no choice and returns NaN.

Back to the implementation. We want an automatic test, to quick start the program on different hardware and software settings. With a nice console output what happens, and what happens wrong.
There are two ways to do this. The easy one with lots of code duplication. And the right on, with only on test() function which get called for one test.
The test() function gets a varliable a, b which we wanna test. x als the expected result. A procedure pointer to either min() or max() and a short string with the function name we wanna test. For example:

call test(func, "min", 3.0, NAN, 3.0);

But... one can not get a procedure pointer on a intrinsic function!?? And if you implement your own function, it has to be a subroutine!??

Fortran is broken by design.

This ends up in lot more code and paint than is has to. See my next post where I implement this test in C++. Without pain and only half of code size.

Here is the 56line problem:


module test_m
  use, intrinsic :: IEEE_ARITHMETIC
  contains
  
  subroutine test(func, funcname, a, b, x) 
    implicit none
    procedure(), pointer :: func => null()  
    real, intent(in) :: a, b, x
    character(len=*), intent(in) :: funcname
    real :: res
    
    call func(a,b,res)
    write(*,*) funcname, "(",a, ",", b, ") =", res
    
    if(ieee_is_nan(x)) then
      if(.not. ieee_is_nan(res)) then
        write(*,*) "But sould be", x
      endif
    else if(res /= x) then
      write(*,*) "But should be", x
    endif    
  end subroutine

  subroutine mymin(a,b, x)
    implicit none
    real, intent(in) :: a, b
    real, intent(out) :: x
    x = min(a,b)
  end subroutine
  
  subroutine mymax(a,b, x)
    implicit none
    real, intent(in) :: a, b
    real, intent(out) :: x
    x = max(a,b)
  end subroutine
end module

program fmin    
  use test_m
  implicit none
  real :: NAN
  procedure(), pointer :: func => null()
  
  NAN = IEEE_VALUE(NAN, IEEE_QUIET_NAN)

  func => mymin  
  call test(func, "min", -3.0, NAN, -3.0)
  call test(func, "min", NAN, -3.0, -3.0)
  call test(func, "min", NAN, NAN,  NAN)

  func => mymax  
  call test(func, "max", -3.0, NAN, -3.0)
  call test(func, "max", NAN, -3.0, -3.0)
  call test(func, "max", NAN, NAN,  NAN)
end program

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress