views:

506

answers:

5

Hi, this is my first time trying to program in Fortran. I'm trying to write a program that prints the first 1476 terms of the Fibonacci sequence, then examines the first digit of each term and stores the number of 1s, 2s, 3s, ..., 9s that occur in an array.

The problem that I can't seem to figure out is how to read the first digit of each term. I've tried several things but am having difficulty with my limited knowledge of Fortran techniques. I write the terms to a text file and the idea is to read the first digit of each line and accumulate the respective number in the array. Does anyone have any suggestions of how to do this?

Here is my code so far:

(edit: I included the code I have for reading the file. Right now it just prints out 3.60772951994415996E-313, which seems like an address of some sort, because it's not one of the Fibonacci numbers. Also, it is the only thing printed, I expected that it would print out every line of the file...)

(edit edit: After considering this, perhaps there's a way to format the writing to the text file to just the first digit. Is there a way to set the number of significant digits of a real number to one? :P)

subroutine writeFib(n)
  integer ::  i
  real*8 :: prev, current, newFib
  prev = 0
  current = 1
  do i = 1, n
     newFib = prev + current
     prev = current
     current = newFib
     write(7,*) newFib
  end do
  return
end subroutine

subroutine recordFirstDigits(a)
  integer :: openStat, inputStat
  real*8 :: fibNum
  open(7, file = "fort.7", iostat = openStat)
  if (openStat > 0) stop "*** Cannot open the file ***"
  do
     read(7, *, iostat = inputStat) fibNum
     print *,fibNum
     if (inputStat > 0) stop "*** input error ***"
     if (inputStat < 0) exit ! end of file
  end do
  close(7)
end subroutine

program test
  integer :: k, a(9)
  k = 1476
  call writeFib(k)
  call recordFirstDigits(a)
end program
+1  A: 

Can you read with a FORMAT(A1)? It's been 20 years so I don't remember the exact syntax.

Paul Tomblin
A: 

I am getting an 'end of line' runtime error

You don't show the ! code to read here... which makes it kind of difficult to guess what you are doing wrong :-)

Perhaps you need a loop to read each line and then jump out of the loop to a continue statement when there are no more lines.

Something like this:

   do
      read(7,*,end=10) fibNumber
   end do
   10 continue

Better still - look at the more modern style used in this revcomp program.

igouy
+1  A: 

I wonder why the open statement succeeds when file 7 hasn't been closed. I think you need an endfile statement and/or a rewind statement in between writing and reading.

Paul Tomblin posted what you have to do after you solve your problem in getting reads to work in the first place.

Windows programmer
wow, I didn't even notice that...I added close(7) before the return statement in writeFib(n) and it prints everything as expected now :) Yeah, I'm currently looking at the format statements too, thanks for the help
Aaron
+1  A: 

Although the suggestions were in place, there were also several things that were forgotten. Range of the REAL kind, and some formatting problems.

Anyways, here's one patched up solution, compiled and working, so try to see if this will work for you. I've took the liberty of choosing my own method for fibonacci numbers calculation.

  program SO1658805
  implicit none

  integer, parameter :: iwp = selected_real_kind(15,310)
  real(iwp) :: fi, fib
  integer :: i
  character(60) :: line
  character(1) :: digit
  integer :: n0=0, n1=0, n2=0, n3=0, n4=0, n5=0, n6=0, n7=0, n8=0, n9=0

  open(unit=1, file='temp.txt', status='replace')
  rewind(1)
  !-------- calculating fibonacci numbers -------
  fi = (1+5**0.5)/2.
  do i=0,1477
    fib = (fi**i - (1-fi)**i)/5**0.5
    write(1,*)fib,i  
  end do
  !----------------------------------------------
  rewind(1)

  do i=0,1477
    read(1,'(a)')line
    line = adjustl(line)
    write(*,'(a)')line


    read(line,'(a1)')digit

     if(digit.eq.' ') n0=n0+1
     if(digit.eq.'1') n1=n1+1
     if(digit.eq.'2') n2=n2+1
     if(digit.eq.'3') n3=n3+1
     if(digit.eq.'4') n4=n4+1
     if(digit.eq.'5') n5=n5+1
     if(digit.eq.'6') n6=n6+1
     if(digit.eq.'7') n7=n7+1
     if(digit.eq.'8') n8=n8+1
     if(digit.eq.'9') n9=n9+1
  end do
  close(1)

  write(*,'("Total number of different digits")')
  write(*,'("Number of digits 0: ",i5)')n0
  write(*,'("Number of digits 1: ",i5)')n1
  write(*,'("Number of digits 2: ",i5)')n2
  write(*,'("Number of digits 3: ",i5)')n3
  write(*,'("Number of digits 4: ",i5)')n4
  write(*,'("Number of digits 5: ",i5)')n5
  write(*,'("Number of digits 6: ",i5)')n6
  write(*,'("Number of digits 7: ",i5)')n7
  write(*,'("Number of digits 8: ",i5)')n8
  write(*,'("Number of digits 9: ",i5)')n9

  read(*,*)

  end program SO1658805

Aw, ... I just read you need the number of digits stored in to an array. While I just counted them.

Oh well, ... "left as an exercise for the reader ..." :-)

ldigas
Thanks for the reply. Interestingly enough, I ended up doing a similar approach (except that I converted the number to a string and parsed it to get the first value). For the last fibonacci value I got +infinity, so does selected_real_kind(15,310) have a larger range than real*8?
Aaron
Ok, just tried your iwp trick and it actually gives me the last value now, thanks! :)
Aaron
That depends on the compiler/processor ... in any case, if one desires portable precision, one should go with explicitly defining his demands in a custom kind type (the selected_real_kind ...). I do not know what is the range of real*8, since it most probably isn't the same on your and mine system.Anyways, I hope you solved your problem.
ldigas
Oh...that's interesting. I read that real*8 is synonymous with double precision, but I don't know the range of that either. In any case, this has certainly been a learning experience in fortran :P, thanks everyone~
Aaron
Uhmm ... (do not take this out of context), well yes, it is. REAL*4 was considered single, and *8 double precision. But it was nowhere specified what double precision represented. Anyways, if you're interested, look up in the help of your compiler, RANGE and PRECISION functions. Using them you can determine the range and precision (duh :) of your data type.
ldigas
A: 

Hello Aaron, here are some hints:

  1. You don't need to use characters, much less file i/o for this problem (unless you forgot to state that a file must be created).
  2. Therefore, use math to find your statistics. There are lots of resources on Fibonacci numbers that might provide a simplifying insight or at least a way to independently spot check your answers.
    • Here is a complicated hint in non-Fortran lingo:
      floor(10^(frac(log_10(7214989861293412))))
      (Put this in Wolfram Alpha to see what it does.)
    • A simpler hint (for a different approach) is that you can do very well in Fortran with simple arithmetic inside of looping constructs--at least for a first pass at the solution.
  3. Accumulate your statistics as you go. This advice would even apply to your character-driven approach. (This problem is ideally suited for coming up with a cute indexing scheme for your statistics, but some people hate cute schemes in programming. If you don't fear cuteness ... then you can have associative arrays in Fortran as long as your keys are integers ;-)
  4. The most important aspect of this problem is the data type you will use to calculate your answers. For example, here's the last number you will have to print.

Cheers, --Jared

jaredor