program sprngtest !======================================================================= ! Written by T. M. DeBoni, NERSC User Services, May 5, 2000. !----------------------------------------------------------------------- ! ! This program tests the parallel pseudorandom number generator library ! SPRNG 1.0. It is designed to generate multiple streams of random ! numbers of various formats and ranges. It performs some elementary ! statistical calculations on the streams and print out the results in ! 64-bit hexadecimal notation, to allow full comparisons among platforms. ! ! Directions for NERSC Usage: ! =========================== ! Access the library by loading the SPRNG module with the command ! module load sprng ! ! Then compile this program file, "sprngtest.F", with the command ! mpxlf90 $SPRNG -o sprngtest -bmaxdata:0x40000000 -bmaxstack:0x40000000 \ ! -qfloat=nomaf -qarch=pwr3 -qtune=pwr3 -qfixed=80 -llcg sprngtest.F ! ! Finally, execute it with the line ! poe sprngtest < sprngtest.inp > sprngtest.out -nodes 1 -tasks_per_node 8 ! ! The input file "sprngtest.inp" could have the following contents: ! 16 1 10000000 ! Note: the above consists of three i10 fields (i.e., 3 10-digit integers, ! right-justified in their fields). ! ! The above input and execution specs allow for 16 streams of 10^7 values ! each, in 8 MPI tasks, or two streams per task. This requires that each ! task allocate space for a 20,000,000 element array of real*8 values, or ! 160 megabytes of storage. The compilation line used will allow for more ! storage to be used if desired, but the parameter "MaxNumberofNumbers" ! is curently set to 500000000 and may need to be changed. ! ! The other SPRNG generators may be substituted for "lcg", in the above ! compilation by substituting any of "cmrg", "lfg", "lcg64", or "mlfg"; ! no changes to the program are needed to use these alternate generators. ! ! The input can also be provided via standard input, and it consists of ! the total number of streams to generate, a seed flag, and the number ! of random numbers to generate per task. These values control the ! program as follows: ! 1) The number of streams controls how many independent streams of ! random numbers SPRNG will create and manage. This value is related ! to the amount of parallelism used in executing the program; the ! number of streams divided by the number of MPI tasks gives the ! number of streams generated per task. ! 2) The seed flag controls how SPRNG initializes its generators; if it ! is zero, all processes get zero as their initial seeds; if it is ! one, all processes get a special value, 985456376, as their initial ! seeds; if it is greater than one, all tasks use it as their initial ! seeds; and if it is less than zero, each task generates its own ! random seed value. ! 3) The number of random numbers is the number of values to be generated ! from each stream (i.e., each task). ! ! The suppression of platform-specific fast arithmetic operations and ! forced compliance with IEEE arithmetic specified above, allows this ! program to produce the same statistical answers, given identical ! parallelism, on the two systems. The SPRNG package is guaranteed to ! produce identical streams, under identical parallelism conditions, on ! these systems, but other arithmetic divergences may occur if such ! compilation options are not used. Optimization level may affect these ! actions. ! ! Allowance for debugging is made by the presence of commented output ! statements. Allowance for output from each task into a separate file ! is made, but not used. Minimal output of computed statistics and ! other functions on the random values is produced, just so the program ! will do some actual calculation. It runs in a couple of minutes. !----------------------------------------------------------------------- implicit none !======================================================================= ! ! I N C L U D E D S T U F F ! !======================================================================= ! ! The CHECK_POINTERS macro is used for debugging, and elided otherwise. !#define CHECK_POINTERS ! The POINTER_SIZE macro is needed on the T3E and elided on the SP. !#define POINTER_SIZE 8 #define USE_MPI #include #include "sprng_f.h" !======================================================================= ! ! C O N S T A N T D E F I N I T I O N S ! !======================================================================= ! !**** Other control values: !**** -------------------- ! integer IZero, Inunit, IOutunit, IRstunit, MyTrue, MyFalse ! parameter ( IZero = 0, Inunit = 5, IOutunit = 6, ! 1 IRstunit = 7, MyTrue = 1, MyFalse = 0 ) ! integer MaxNumberofNumbers ! parameter ( MaxNumberofNumbers = 500000000 ) !======================================================================= ! ! S T O R A G E D E F I N I T I O N S ! !======================================================================= ! integer ProcStatSize parameter (ProcStatSize=4) integer NumberofStreams, SeedFlag, NumberofRandNums, 1 MyNumOfStreams integer numprocs, myid, ierr, tag integer seed, iseed, junk integer i, ii, j, k, k1, k2, l, unitnum, ifirst, ilast SPRNG_POINTER junkPtr integer sj, smyid, snumprocs, sseed integer, dimension(MPI_STATUS_SIZE) :: status real*8 RandNum real*8 inv_nrn, inv_nrnm1, one_real8 real*8 SumMeans, SumSqMeans, SumVariances, SumSqVariances, 1 MeanOfMeans, MeanOfVariances, 2 VarianceOfMeans, VarianceOfVariances real*8 SumProcMeans, SumProcSqMeans, SumProcVariances, 1 SumProcSqVariances, MeanOfProcMeans, VarianceOfProcMeans, 2 MeanOfProcVariances, VarianceOfProcVariances real*8, dimension(0:ProcStatSize-1) :: ProcStats real*8, dimension(:), allocatable :: RandNums, Sum, SumSq, buff real*8, dimension(:), allocatable :: Mean, Variance real*8, dimension(:,:), allocatable :: AllMeans, AllVariances, 1 AllProcStats SPRNG_POINTER, dimension(:), allocatable :: streamPtr real*8 wastedtime, result !======================================================================= ! ! M A I N P R O G R A M ! !======================================================================= !**** Initialize the MPI mechanisms call MPI_INIT(ierr) call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr ) call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr ) !**** Set up input and output files; all processors do this. ! call FileSetup(myid, unitnum) !**** Read the input data; only the master does this. if(myid .eq. 0) call GetInput( NumberofStreams, SeedFlag, 1 NumberofRandNums ) !**** Broadcast the input values; all processors do this. call MPI_BCAST(NumberofStreams, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) call MPI_BCAST(SeedFlag, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) call MPI_BCAST(NumberofRandNums, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) !**** Initialize the parallel random number generator to the number of !**** separate streams specified by the amount of parallelism needed. !**** All processors do this. if( SeedFlag .eq. 0 ) then !....... All procs get seed zero seed = 0 elseif( SeedFlag .eq. 1 ) then !....... All procs get seed advised in SPRNG 1.0 documentation seed = 985456376 elseif( SeedFlag .gt. 1 ) then !....... All procs get seed value read in as SeedFlag seed = SeedFlag else !....... SeedFlag .lt. 0 means all procs generate their own random seed values seed = make_sprng_seed() endif !**** Determine how many streams each processor has; all processors do this. if( NumberofStreams .ge. numprocs ) then if( mod( NumberofStreams, numprocs ) .eq. 0 ) then !**** ..... All is ok MyNumOfStreams = NumberofStreams / numprocs if( myid .eq. 0 ) then write( *, 200 ) MyNumOfStreams 200 format( " Each process will generate ", i4, " streams." ) endif else !**** ..... This processor can't continue write( *, 201 ) myid, NumberofStreams, numprocs, 1 mod( NumberofStreams, numprocs ) 201 format( " ERROR: proc ", i4, " NumberofStreams .ge. numprocs", 1 " but ", /, 2 " mod( NumberofStreams, numprocs ) .ne. 0 ", /, 3 " ", i14, " .ge. ", i4, ", but ", i4, 4 " .ne. 0 " ) call MPI_FINALIZE(ierr) stop "ERROR: NumberofStreams >= numprocs, mod(a,b) <> 0" endif else !**** .. No processes can continue write( *, 202 )myid, NumberofStreams, numprocs 202 format( " ERROR: Process ", i4, " NumberofStreams .lt. numprocs ", 1 /, " ", i14 , " .lt. ", i4 ) call MPI_FINALIZE(ierr) stop "ERROR: NumberofStreams < numprocs" endif !**** Allocate local data structures; all processors do this. allocate(RandNums(MyNumOfStreams*NumberofRandNums)) allocate(streamPtr(0:MyNumOfStreams-1)) allocate(Sum(0:MyNumOfStreams-1)) allocate(SumSq(0:MyNumOfStreams-1)) allocate(Mean(0:MyNumOfStreams-1)) allocate(Variance(0:MyNumOfStreams-1)) !**** Allocate global data structures; only master does this. if( myid .eq. 0) then allocate(AllMeans(0:numprocs-1, 0:MyNumOfStreams-1)) allocate(AllVariances(0:numprocs-1, 0:MyNumOfStreams-1)) allocate(AllProcStats(0:numprocs-1, 0:ProcStatSize-1)) allocate(buff(0:max(MyNumOfStreams,ProcStatSize)-1)) endif !**** Print info about each stream; all processors do this, !**** sequentially, by process number, optionally wasting some !**** time to allow the output to get out. ! do 105 i = 0, numprocs ! call timewaste(0, wastedtime) ! if( i .eq. myid ) then do 104 j = 0, MyNumOfStreams-1 sj = j + myid * MyNumOfStreams streamPtr(j) = init_sprng(sj, NumberofStreams, seed, 1 SPRNG_DEFAULT) ! write( *, 203 )myid, j, sj, streamPtr(j) ! 203 format( " ******************************", /, ! 1 " INIT: Process ", i4, ", stream ", i4, ! 2 " globalstreamid ", i4, " ptr ", z16.16, ":" ) ! junk = print_sprng(streamPtr(j)) 104 continue ! endif ! call timewaste(0, wastedtime) ! 105 continue !**** Generate the streams and data from them; all processors do this. ! write(unitnum, 910) myid ! 910 format( " Proc: ", i4 ) do 108 j = 0, MyNumOfStreams-1 Sum(j) = 0.0 SumSq(j) = 0.0 do 106 i = 1, NumberofRandNums RandNum = sprng(streamPtr(j)) ii = j*NumberofRandNums + i RandNums( ii ) = RandNum Sum(j) = Sum(j) + RandNum SumSq(j) = SumSq(j) + RandNum*RandNum ! write(*, 911) ii, j, RandNum, Sum(j), SumSq(j) ! 911 format( " num ", i9, " stream ", i4, " = ", ! 1 z16.16, "; Sum(j) = ", z16.16, " SumSq(j) = ", z16.16 ) 106 continue !**** Do some meaningless computations with the random numbers generated call compute(RandNums, j, NumberofRandNums, result) write(*, 207) myid, j, result 207 format( " Proc ", i4, " stream ", i4, " result ", g21.14 ) 108 continue !**** Set up some constants and report their values, and those of !**** some accumulators; all processors do this. one_real8 = 1.0 inv_nrn = one_real8 / NumberofRandNums inv_nrnm1 = one_real8 / (NumberofRandNums-1) ! write(unitnum, 900) one_real8, inv_nrn, inv_nrnm1 ! 900 format( " one_real8 = ", z16.16, " inv_nrn = ", z16.16, ! 1 " inv_nrnm1 = ", z16.16 ) !**** Calculate the stats on each stream; all processors do this. do 109 j = 0, MyNumOfStreams-1 ! write(unitnum, 901) j, Sum(j), j, SumSq(j) ! 901 format( " Sum(", i4, ") = ", z16.16, ! 1 " SumSq(", i4, ") = ", z16.16 ) if(NumberofRandNums .gt. 1) then Mean(j) = Sum(j) * inv_nrn Variance(j) = SumSq(j) - (Sum(j)*Sum(j))*inv_nrn Variance(j) = Variance(j)*inv_nrnm1 else Mean(j) = Sum(j) Variance(j) = 0.0 endif 109 continue !**** Calculate the aggregate stats; all processors do this. SumMeans = 0.0 SumSqMeans = 0.0 SumVariances = 0.0 SumSqVariances = 0.0 do 110 j = 0, MyNumOfStreams-1 SumMeans = SumMeans + Mean(j) SumSqMeans = SumSqMeans + Mean(j)*Mean(j) SumVariances = SumVariances + Variance(j) SumSqVariances = SumSqVariances + Variance(j)*Variance(j) 110 continue if(MyNumOfStreams .gt. 1) then MeanOfMeans = SumMeans / float(MyNumOfStreams) MeanOfVariances = SumVariances / float(MyNumOfStreams) VarianceOfMeans = (SumSqMeans - SumMeans*SumMeans/ 1 float(MyNumOfStreams))/ 2 float(MyNumOfStreams-1) VarianceOfVariances = (SumSqVariances - SumVariances*SumVariances/ 1 float(MyNumOfStreams))/ 2 float(MyNumOfStreams-1) else MeanOfMeans = SumMeans MeanOfVariances = SumVariances VarianceOfMeans = 0.0 VarianceOfVariances = 0.0 endif ProcStats(0) = MeanOfMeans ProcStats(1) = MeanOfVariances ProcStats(2) = VarianceOfMeans ProcStats(3) = VarianceOfVariances !**** Either send or receive the stats ! !**** Slaves send: Means get tag=myid, in (1..numprocs-1) !**** Variances get tag=myid+numprocs, in (numprocs+1..2*numprocs-1) !**** ProcStats get tag=myid+(2*numprocs), in (2*numprocs+1..3*numprocs-1) if( myid .ne. 0) then ! write( unitnum, 212 ) myid, myid, MyNumOfStreams ! 212 format( " Process ", i4, " sending tag ", i4, " size ", i4 ) call MPI_SEND( Mean, MyNumOfStreams, MPI_REAL8, 0, 1 myid, MPI_COMM_WORLD, ierr ) ! write( unitnum, 212 ) myid, numprocs+myid, MyNumOfStreams call MPI_SEND( Variance, MyNumOfStreams, MPI_REAL8, 0, 1 numprocs+myid, MPI_COMM_WORLD, ierr ) ! write( unitnum, 212 ) myid, 2*numprocs+myid, ProcStatSize call MPI_SEND( ProcStats, ProcStatSize, MPI_REAL8, 0, 1 2*numprocs+myid, MPI_COMM_WORLD, ierr ) !**** Master receives: !**** Master already has own data else do 113 k1 = 0, MyNumOfStreams-1 AllMeans(0, k1) = Mean(k1) AllVariances(0, k1) = Variance(k1) 113 continue AllProcStats(0, 0) = ProcStats(0) AllProcStats(0, 1) = ProcStats(1) AllProcStats(0, 2) = ProcStats(2) AllProcStats(0, 3) = ProcStats(3) !**** Master receives three messages from each slave do 116 k = 1, 3*(numprocs-1) call MPI_RECV( buff, max(MyNumOfStreams,ProcStatSize), MPI_REAL8, 1 MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, 2 status, ierr ) tag = status(MPI_TAG) if( tag .gt. 2*numprocs ) then !**** ....... ProcStats will get tagmyid+2*numprocs, !**** ....... so tag will be in (2*numprocs+1..3*numprocs-1) ! write( unitnum, 214 ) myid, tag, ProcStatSize ! 214 format( " Process ", i4, " received tag ", i4, " size ", i4 ) AllProcStats(tag-2*numprocs, 0) = buff(0) AllProcStats(tag-2*numprocs, 1) = buff(1) AllProcStats(tag-2*numprocs, 2) = buff(2) AllProcStats(tag-2*numprocs, 3) = buff(3) elseif( tag .gt. numprocs ) then !**** ....... Variances get tag=myid+numprocs, !**** ....... so tag will be in (numprocs+1..2*numprocs-1) ! write( unitnum, 214 ) myid, tag, ProcStatSize do 114 k1 = 0, MyNumOfStreams-1 AllVariances(tag-numprocs, k1) = buff(k1) 114 continue else !**** ....... Means get tag=myid, !**** ....... so tag will be in (1..numprocs-1) ! write( unitnum, 214 ) myid, tag, ProcStatSize do 115 k1 = 0, MyNumOfStreams-1 AllMeans(tag, k1) = buff(k1) 115 continue endif 116 continue endif !**** Master writes out summary stats if( myid .eq. 0) then write( *, 215 ) numprocs, MyNumOfStreams, NumberofRandNums 215 format( /, 1 " Stats on ", i4, " sets of ", i4, " streams of ", i8, 2 " random numbers:", / ) do 126 k1 = 0, numprocs-1 do 124 k2 = 0, MyNumOfStreams-1 write( *, 221 ) k1, k2, AllMeans(k1,k2), AllMeans(k1,k2), 1 k2, AllVariances(k1,k2), AllVariances(k1,k2) 221 format( " Proc ", i4, ": AllMeans(", i4, ") = ", z16.16, 1 " = ", g21.14, /, 2 " AllVariances(", i4, ") = ", z16.16, 3 " = ", g21.14 ) 124 continue write( *, 225 ) k1, (AllProcStats(k1,l), AllProcStats(k1,l), l=0,3) 225 format( " Summary for Proc ", i4, ":", /, 1 " Mean of Means = ", z16.16, " = ", g21.14, /, 1 " Mean of Variances = ", z16.16, " = ", g21.14, /, 2 " Variance of Means = ", z16.16, " = ", g21.14, /, 3 " Variance of Variances = ", z16.16, " = ", g21.14, / ) 126 continue endif !**** Master generates master stats if(myid .eq. 0) then SumProcMeans = 0.0 SumProcSqMeans = 0.0 SumProcVariances = 0.0 SumProcSqVariances = 0.0 do 130 i = 0, numprocs-1 SumProcMeans = SumProcMeans + AllProcStats(i,0) SumProcSqMeans = SumProcSqMeans + 1 AllProcStats(i,0)*AllProcStats(i,0) SumProcVariances = SumProcVariances + AllProcStats(i,1) SumProcSqVariances = SumProcSqVariances + 1 AllProcStats(i,1)*AllProcStats(i,1) 130 continue if(numprocs .gt. 1) then MeanOfProcMeans = SumProcMeans / float(numprocs) VarianceOfProcMeans = (SumProcSqMeans - SumProcMeans*SumProcMeans/ 1 float(numprocs))/ 2 float(numprocs-1) MeanOfProcVariances = SumProcVariances / float(numprocs) VarianceOfProcVariances = (SumProcSqVariances - 1 SumProcVariances*SumProcVariances/ 2 float(numprocs))/ 3 float(numprocs-1) else MeanOfProcMeans = SumProcMeans VarianceOfProcMeans = 0.0 MeanOfProcVariances = SumProcVariances VarianceOfProcVariances = 0.0 endif endif !**** Master writes out master stats if(myid .eq. 0) then if(numprocs .le. 1) then write( *, 231 ) 231 format( " Single processor execution invalidates Master Stats." ) else write( *, 232 ) MeanOfProcMeans, MeanOfProcMeans, 1 VarianceOfProcMeans, VarianceOfProcMeans, 2 MeanOfProcVariances, MeanOfProcVariances, 3 VarianceOfProcVariances, VarianceOfProcVariances 232 format( " Master Stats:", /, " =============", /, 1 " Mean Of Proc Means = ", z16.16, " = ", g21.14, /, 2 " Variance Of Proc Means = ", z16.16, " = ", g21.14, /, 3 " Mean Of Proc Variances = ", z16.16, " = ", g21.14, /, 4 " Variance Of Proc Variances = ", z16.16, " = ", g21.14 ) endif endif !**** Wait until everyone is done before cleaning up and quitting call MPI_Barrier(MPI_COMM_WORLD, ierr) !**** Terminate all random number streams; all processors do this. do 142 i = 0, numprocs do 140 j = 0, MyNumOfStreams-1 sj = j + myid * MyNumOfStreams if( myid .eq. i ) then ifirst = j*NumberofRandNums + 1 ilast = ifirst + NumberofRandNums-1 write( *, 290 ) myid, j, sj, 1 ifirst, RandNums(ifirst), 2 ilast, RandNums(ilast) 290 format( " Proc ", i4, " ends strm ", i4, " glstrmid ", i4, 1 " RN(", i9, ") = ", g21.14, 2 " RN(", i9, ") = ", g21.14 ) endif junk = free_sprng(streamPtr(j)) 140 continue 142 continue !**** Close all the files; all processors do this. ! call CloseFile(myid) !**** Terminate MPI ! write( *, 997 ) ! 997 format( " Terminating MPI " ) 998 call MPI_FINALIZE(ierr) !**** All done write( *, 999 ) 999 format( " Terminating execution " ) stop "Normal Termination." end ! end Main !======================================================================= ! ! D A T A S T R U C T U R E M A N I P U L A T I O N C O D E ! !======================================================================= !======================================================================= ! ! A U X I L I A R Y R O U T I N E S ! !======================================================================= subroutine CloseFile(procid) !----------------------------------------------------------------------- integer procid, unitnum !----------------------------------------------------------------------- ! write( *, 10 ) procid !10 format( " CloseFile: procid = ", i4, /, ! 1 " ----------" ) unitnum = procid + 10 close( unitnum ) ! write( *, 60 ) procid, unitnum !60 format( " CloseFile: procid = ", i4, " unitnum = ", i4 ) return end ! end CloseFile !======================================================================= subroutine FileSetup(procid, unitnum) !----------------------------------------------------------------------- character*23 InputFileName, OutputFileName character(len=15) filename character(len=2) idstring integer procid, unitnum, istat !----------------------------------------------------------------------- ! write( *, 10 ) !10 format( ' Enter name of file containing data tuples: ' ) ! read( *, 20 ) InputFileName !20 format( A ) ! write( *, 30 ) !30 format( ' Enter name of file to receive all text output: ' ) ! read( *, 40 ) OutputFileName !40 format( A ) ! open( file=InputFileName, unit=Inunit ) ! open( file=OutputFileName, unit=IOutunit ) if( procid .le. 9 ) then write( idstring, 51 ) procid 51 format(i1) else write( idstring, 52 ) procid 52 format(i2) endif idstring = trim(idstring) filename = "sprngtest.out" // idstring filename = trim(filename) unitnum = procid + 10 open( file=filename, action="WRITE", 1 unit=unitnum, iostat=istat ) ! write( *, 60 ) procid, filename, unitnum, istat !60 format( " FileSetup: procid = ", i4, " filename = ", a, ! 1 " unitnum = ", i4, " istat = ", i4 ) return end ! end FileSetup !======================================================================= subroutine GetInput( NumberofStreams, SeedFlag, NumberofRandNums ) !----------------------------------------------------------------------- integer NumberofStreams, SeedFlag, NumberofRandNums !----------------------------------------------------------------------- write( *, 10 ) 10 format( ' GetInput: Enter three ten-digit integer values for', /, 1 ' the total number of streams, the seed flag, and the', /, 2 ' number of random values per stream:' ) !**** Read the control values. read( *, 20 ) NumberofStreams, SeedFlag, NumberofRandNums 20 format( 3i10 ) write( *, 30 ) NumberofStreams, SeedFlag, NumberofRandNums 30 format( " GetInput: ", 3i10 ) !**** Echo the control values. write( *, 110 ) NumberofStreams, SeedFlag, NumberofRandNums 110 format( ' INPUT DATA:', /, 1 ' NumberofStreams = ', i10, ' SeedFlag = ', i10, 2 ' NumberofRandNums = ', i10, / ) ! write( *, 210 ) !210 format( 'Closing input file.', / ) !**** All done with the input file. ! close( Inunit ) return end ! end GetInput !======================================================================= subroutine PutOutput( ) !----------------------------------------------------------------------- !----------------------------------------------------------------------- ! write( *, 100 ) !100 format( ' OUTPUT DATA:', /, '============' ) return end ! end PutOutput !======================================================================= subroutine compute(rns, jstream, n, result) real*8, dimension(1:n) :: rns real*8 result, func, diff integer jstream, n, iflr, iceil, i ! write(*, 200) ! 200 format( 10x, " compute",/, 10x, " =======" ) ! write(*, 201) jstream, n ! 201 format( 10x, " jstream = ", i9, " n = ", i9 ) iflr = jstream*n + 1 iceil = jstream*n + n ! write(*, 202) iflr, iceil ! 202 format( 10x, " iflr = ", i9, " iceil = ", i9 ) ! write(*, 203) (rns(i), i=iflr, iceil) ! write(*, 203) rns(iflr), rns(iceil) ! 203 format( 10x, " rand nums = ", 2(g21.14, x) ) result = 0.0d0 do 100 i = iflr, iceil func = dsin(dasin(dcos(dacos(dlog(dexp(rns(i))))))) diff = abs(rns(i) - func) result = result + diff 100 continue ! write(*, 204) result ! 204 format( 10x, " result = ", g21.14 ) return end !======================================================================= subroutine timewaste(n, sum) integer n real*8 sum, sum1 real*8, dimension(:), allocatable :: a allocate(a(n)) do 100 i = 1, n a(i) = sin(cos(exp(log(float(i))))) 100 continue sum = 0.0 do 300 i = 1, n sum1 = 0.0 do 200 j = 1, i sum1 = sum1 + a(i) 200 continue sum = sum + sum1 300 continue return end !=======================================================================