Leibniz_binary_system_1697_cropped.jpg

Universal Numbers (unum) in Fortran

Updating code with derived types

I spent yesterday getting back into the unum code, and I quickly realized how my previous stubbornness around using only 64-bit integers as containers for the unums instead of using some sort of user-defined data type was making the code way more difficult to understand. On top of that, without unique data types, the code is a lot more prone to error and there were some compromises, like using exact floating point equivalence (think "x == 1.0") that were making me uncomfortable.

But what about the performance hit? After all, why do all this work in Fortran if all the bells and whistles will just slow it down? So to do a very basic test to see how derived types might impact performance, I wrote this short program. 

program oo_speed_test
  use ISO_FORTRAN_ENV
  implicit none

  type :: int_container
    integer (INT64) :: val
  end type int_container

  real  (REAL64):: t, t1
  integer (INT64) :: i
  integer (INT64) :: x, y
  type (int_container) :: a, b

  y=1
  x=0

  call cpu_time (t)
  do i = 1, 1000000000
    x = y + x
  end do
  call cpu_time (t1)
  print *, 'Elapsed time for bare integer is ', t1-t

  a%val=1
  b%val=0
  call cpu_time (t)
  do i = 1, 1000000000
    b%val = a%val + b%val
  end do
  call cpu_time (t1)
  print *, 'Elapsed time for derived integer is ', t1-t

end program oo_speed_test

Amazingly, the second loop is slightly faster than the first. The normal integer loop executes in about 1.65s on my computer (using default compiler options) with the derived type loop taking about 1.55s. Perhaps the more computer savvy among you can tell me why this could be, but for now I'm satisfied with at least some sign that using derived types won't cripple the execution speed of the unum code.  

So, with this assurance, I created three types:

  1. unum_t: Contains one field, u, which is a 64-bit integer
  2. ubound_t: Contains a vector, ub, of two unum_t numbers
  3. general_interval_t: Contains two vectors. One vector, endpoints, is of length two and contains the real numbers representing the end points of the interval. The second vector, are_closed, contains two boolean/logical values indicating whether the corresponding end point is opened or closed.

Another great benefit to derived types is that I can create interfaces for them in the default Fortran operators and intrinsic functions. For instance, I can now say that "a==b", where both a and b are unums, and I can do the bitwise operations iand and ieor for pure unum inputs. Eventually, this will also let me use normal operators like +, -, *, /, etc. with unums, so people using this package won't have to think about bit logic or internal representations in order to use them. Ideally, this would also allow previously written code to be updated with unums pretty painlessly; just add the package, redefine certain variables to be unums, and that should be mostly it.    

Speaking of basic math, that should be in the next round of updates, which will hopefully be coming soon.

David PernerComment