The cost of underflows: some empirical data
David Hough
uunet!Eng.Sun.COM!David.Hough
Wed Sep 1 11:38:12 PDT 1993
Here's a little short program I've used for testing IEEE underflow/subnormal
performance. Be
careful, not all Fortran compilers handle 2.0e0**(-149) and 2.0d0**(-1074)
correctly. _PLAIN_UNIX is for systems other than SunOS that don't have
a way of enabling abrupt underflow.
The timing and random number routines may require some attention, as is often
the case when porting Fortran 77 programs.
#ifdef __hpux
#define STDERR 7
#else
#define STDERR 0
#endif
#define STDOUT 6
#ifdef SP
#define REAL real
#define MINNORM (2.0e0**(-126))
#define MINSUB (2.0e0**(-149))
#endif
#ifdef DP
#define REAL doubleprecision
#define MINNORM (2.0d0**(-1022))
#define MINSUB (2.0d0**(-1074))
#endif
#ifdef QP
#define REAL real*16
#define MINNORM (2.0q0**(-16382))
#define MINSUB (2.0q0**(-16494))
#endif
#define N 20000 /* size of vectors */
#define M 10 /* repetition count */
program fastmode
REAL x(N,3), y(N,3), z(N)
logical gradual
integer i
do 1 i = 1,3
call setup(i,x(1,i),y(1,i),N)
1 continue
#ifdef _PLAIN_UNIX
if (gradual()) then
write (STDOUT,*)
1 ' results for gradual underflow/subnormal/exp cases '
write (STDERR,*)
1 ' results for gradual underflow/subnormal/exp cases '
call dotests(M,0,x,y,z,N)
else
write (STDOUT,*)
1 ' results for abrupt underflow/subnormal/exp cases '
write (STDERR,*)
1 ' results for abrupt underflow/subnormal/exp cases '
call dotests(M,1,x,y,z,N)
endif
#else
write (STDOUT,*)
1 ' results for abrupt underflow/subnormal/exp cases '
write (STDERR,*)
1 ' results for abrupt underflow/subnormal/exp cases '
call dotests(M,1,x,y,z,N)
write (STDOUT,*)
1 ' results for gradual underflow/subnormal/exp cases '
write (STDERR,*)
1 ' results for gradual underflow/subnormal/exp cases '
call dotests(M,0,x,y,z,N)
#endif
end
subroutine dotests(reps,abrupt,x,y,z,n)
REAL x(n,3), y(n,3), z(n)
REAL abrupttimes(3)
integer n, reps, abrupt
doubleprecision check
doubleprecision t1, r, u, s
integer i,j
real*4 dtime,tarray(2)
do 1 i = 1, 3
#ifndef _PLAIN_UNIX
if (abrupt .eq. 1) then
call abrupt_underflow
endif
#endif
#ifdef __NEWVALID
call startvalidtime
#else
t1=dtime(tarray)
#endif
do 3 j = 1, reps
call test(i,x(1,i),y(1,i),z,n)
3 continue
#ifdef __NEWVALID
call validtime(r,u,s)
t1=u+s
#else
t1=dtime(tarray)
#endif
if (abrupt .eq. 1) then
abrupttimes(i)=t1
#ifndef _PLAIN_UNIX
call gradual_underflow
#endif
endif
check = 0
do 2 j = 1,N
check = check + z(j)
c print *,j,z(j)
2 continue
write(STDOUT,*) ' test ',i,' checksum ',check
if (i .eq. 3) then
write(STDERR,*) ' test ',i,' KFLOPS ',
1 nint(10*reps*(N/(1000*(t1))))
c exp deserves about 10 FLOPS
else
write(STDERR,*) ' test ',i,' KFLOPS ',
1 nint(reps*(N/(1000*(t1))))
endif
#ifndef _PLAIN_UNIX
if (abrupt.eq.0) then
write(STDERR,*)
1 ' gradual/abrupt ratio ',nint((t1)/abrupttimes(i)),' X'
endif
#endif _PLAIN_UNIX
1 continue
return
end
subroutine test(itest,x, y, z, n)
REAL x(n),y(n),z(n)
integer itest,n,i
goto(1,2,3),itest
1 continue
do 10 i = 1, n
10 z(i) = x(i) * y(i)
goto 9
2 continue
do 20 i = 1, n
20 z(i) = x(i) * y(i)
goto 9
3 continue
do 30 i = 1, n
30 z(i) = exp(x(i))
goto 9
9 continue
end
subroutine setup(itest,x,y,n)
REAL x(n),y(n)
integer itest,n,i
doubleprecision u
#ifdef __NEWVALID
doubleprecision doublevalidrandom
#define dorand(X) doublevalidrandom()
#else
doubleprecision dorand
#endif
goto(1,2,3),itest
1 continue
do 10 i = 1, n
u = dorand(0)
x(i) = sqrt(MINSUB) *
1 (MINNORM/MINSUB)**(u/2)
u = dorand(0)
y(i) = sqrt(MINSUB) *
1 (MINNORM/MINSUB)**(u/2)
10 continue
goto 9
2 continue
do 20 i = 1, n
u = dorand(0)
x(i) = MINNORM *
1 (MINSUB/MINNORM)**u
u = dorand(0)
y(i) = (MINNORM/MINSUB) *
1 ((MINSUB/MINNORM)/MINNORM) ** u
20 continue
goto 9
3 continue
do 30 i = 1, n
30 x(i) = -i
goto 9
9 continue
end
#ifndef __NEWVALID
double precision function dorand(n)
integer n
real rand
#ifdef _AIX
dorand = rand()
#else
dorand = rand(n)
#endif
end
#endif
REAL function dummy(t)
REAL t
dummy = t
end
logical function gradual()
REAL t,t1,t2,delta,dummy
integer i
t = 1
t1=1
t2=1
do 1 i = 1,1000000
t2=t1
t1=t
t = dummy(0.5*t)
if (t .ge. t1) goto 2
1 continue
2 continue
delta = (dummy(1.01 * t2) - t2)/t2
if ((delta .gt. .005).and.(delta .lt. .02)) then
gradual = .false.
else
gradual = .true.
endif
end
More information about the Numeric-interest
mailing list