Obtaining larger integers in Fortran [duplicate] - fortran

This question already has answers here:
Fortran: handling integer values of size: ~700000000000
(6 answers)
How do I do big integers in Fortran?
(1 answer)
Closed 8 months ago.
I'm trying to write a Fortran code which checks if a user input number is a prime or not. The code is given below,
program cp
implicit none
integer(kind=8) :: nmb, ind
real*16 :: sqnmb, real_nmb
print*, "Largest value for a is ", huge(nmb)
DO
print *,"Enter the number larger than 0:"
read (*,*) nmb
IF ( nmb <= 0) THEN
print *, "Please enter a number larger than 0."
END IF
IF ( nmb > 0) THEN
EXIT
END IF
END DO
sqnmb = sqrt(real(nmb))
do ind= 2, int(sqnmb), 1
IF (mod(nmb,ind) == 0) THEN
print *, "The number", nmb ,"is not a prime, it is divisible by",ind
STOP
END IF
end do
print *, "The number", nmb ,"is a prime"
end program cp
The program works fine for all numbers below 9223372036854775807(19 digits) which is the largest number that can be defined with the integer(kind=8) type. However, I want to calculate for numbers with 25 digits. How can we define larger integers in Fortran?

Related

Fortran prompting user and reading polynomial input

I am writing a program to calculate the roots of a polynomial. The user is prompted a polynomial of no greater than fourth order (not a file read). How do I read a polynomial input in Fortran? I thought about using 1D array, each index representing the degree and the number representing the coefficient, but what about the plus and minus signs? I don't want to restrict the user to a polynomial with one mathematical operation.
If you don't care about pretty printing the polynomial without brackets it's not that difficult:
program prompt_read
implicit none
integer, parameter :: wp = kind(1.0d0) ! work precision
!> Polynomial coefficients (maximum degree = 4), only real values allowed
real(wp) :: a(0:4)
!> Polynomial degree
integer :: n
! initialize coefficients to zero
a = 0
write(*,'(A)',advance='no') "Enter polynomial degree (1-4): "
read(*,*) n
! handle erroneous input
if (n > 4 .or. n < 1) then
write(*,'(A)') 'Input error. Try again.'
stop
end if
write(*,'(A)',advance='no') "Enter polynomial coefficients (ascending powers of x): "
read(*,*) a(0:n)
write(*,'(A)') "The polynomial received was " // polystr(a(0:n))
! ... continue with calculation of roots
contains
pure function polystr(coeffs)
real(wp), intent(in) :: coeffs(0:)
character(len=:), allocatable :: polystr
character(32) :: s
integer :: i
write(s,'("(",F0.3,")")') coeffs(0)
polystr = trim(s)
do i = 1, ubound(coeffs,1)
write(s,'("(",F0.3,")")') coeffs(i)
if (i == 1) then
s = trim(s) // '*x'
else if (i > 1) then
s = trim(s) // '*x^' // achar(iachar('0') + i)
end if
polystr = polystr // ' + ' // trim(s)
end do
end function
end program
Example output:
$ gfortran -Wall -o prompt_read prompt_read.f90
$ ./prompt_read
Enter polynomial degree (1-4): 3
Enter polynomial coefficients (ascending powers): 1,-2,3.,-4.2
The polynomial entered is (1.000) + (-2.000)*x + (3.000)*x^2 + (-4.200)*x^3
A few notes/ideas:
use a custom lower bound of 0 to make the array index match the power of the monomial
you can read both space- or comma-delimited input
the polystr function can only handle polynomials up to degree 9
have a look at polyroots-fortran, a collection of existing polynomial root solvers in Fortran
put the body of the program in an "infinite" do-end do loop with a suitable exit condition (for example upon pressing the key q); add a brief help message to explain usage of the program

Code to Sum up the first 1234 multiples of 3 and 5 does not print anything

I'm trying to write some Fortran 90 code to sum up the first 1234 multiples of 3 and 5 (including multiples of both). Here is my code so far:
program sum
implicit none
integer :: x
integer :: y = 5
integer :: z = 3
integer :: n
if (mod(x,y) == 0 .or. mod(x,z) ==0) then
print *, x
n = x
n = x + x
end if
end program sum
However, this code does not print anything to the terminal.
Your code tests the value of x in the if condition:
if (mod(x,y) == 0 .or. mod(x,z) ==0
but the value of x is not set at all. Therefore the result of the program is completely undefined. You need to create some kind of loop. Better two loops.
The most naive approach is to loop from 1 and test all numbers with the above if condition and stop when you have found the desired number of multiples.

Do-loop ignores if-statement

I'm trying to use an if statement in a do loop which is supposed to generate prime numbers. For that I used modulo to sort out the numbers. After it found a prime number I want it to go a step further and add 1 so that the next prime number can be found and added to the array pzahl. My problem is that the loop seems to ignore that it should go a step further with plauf after it found a prime number so that it just keeps going till infinity... I tried to rearrange the contents of the loop and if statement but it's just not working. Here is the code:
PROGRAM Primzahlen
IMPLICIT NONE
INTEGER :: start, plauf, n, a
INTEGER, ALLOCATABLE, DIMENSION(:) :: pzahlen !array into which the prime numbers should be added
INTEGER :: input
INTEGER, DIMENSION(:), ALLOCATABLE :: alle
PRINT *, "How many prime numbers should be listed"
READ (*,*) input
ALLOCATE (pzahlen(input))
pzahlen(1) = 1
start = 2
plauf = 1
loop1: DO
ALLOCATE(alle(start))
loop2: DO n = 1,start
alle(n)= MODULO(start,n)
END DO loop2
IF (minval(alle) /= 0) THEN ! This is what it seems to ignore.
plauf= plauf + 1
pzahlen(plauf) = start
PRINT *, plauf
END IF
start = start + 1
IF (plauf == eingabe) then
EXIT
END IF
PRINT *, alle
DEALLOCATE(alle)
END DO loop1
PRINT *, "prime numbers:" , pzahlen(1:input)
END PROGRAM Primzahlen
I use the gfortran compiler and write it in Emacs if that helps to know.
It's not ignoring it, it executes correctly:
loop2: DO n = 1,start
alle(n)= MODULO(start,n)
END DO loop2
It doesn't matter what start is, alle(1) will always be zero, as every integer is evenly divisible by 1. That means that minval(alle) will also always be zero, which means that the condition minval(alle) /= 0 is never true, and the statement will never execute.
Added: The last value, alle(start), will also be zero, as every number is evenly divisible by itself.

Count the numbers of equal rows in a file

Suppose you have a file.dat of the form:
1
1
1
2
2
3
3
3
3
...
I want to count how many equal numbers there are and save them iteratively in a string. For instance:
m = 3 (times 1),
m = 2 (times 2),
m = 4 (times 3).
I put here my code:
program sele
implicit none
integer::j,k,s,n,l,r,m
real*8,allocatable::ID(:)
real*8:: j_r8,i_r8
open(10,file='data.dat')
n=0
DO
READ(10,*,END=100)
n=n+1
END DO
100 continue
rewind(10)
allocate(ID(n))
s=0
do s=1, n
read(10,*) ID(s)
end do
do r=1,n-1
if (ID(r)-ID(r+1) .EQ. 0) then
m = m + 1
print*, m
end if
end do
end program
The last do is the condition I'd like to expand, with something like:
if (condition is true) then
save an index of the number of equal digits
use this to do some operations:
do i = 1, number of equal digits
if (condition is not true) then
restart with the other digits.
If the values you want to read are integer values in a given limited range (for instance from 1 to 100), then the simplest way is the following :
program sele
implicit none
integer, parameter :: vmin=1
integer, parameter :: vmax=100
integer :: list(vmin:vmax)
integer :: value,i
open(10,file='data.dat')
list=0
do
read(10,*,end=10) value
if(value < vmin .OR. value > vmax) then
write(*,*) 'invalid value ',value
stop
endif
list(value)=list(value)+1
enddo
10 continue
do i=vmin,vmax
if(list(i) > 0) then
write(*,*) list(i),' times ',i
endif
enddo
end program
Which gives on your example :
3 times 1
2 times 2
4 times 3
It is possible to improve easily that program to manage variable vmin and vmax (the array list must then be declared allocatable and allocated at the right size).
If the range is too large, then a simple array is not accurate anymore and the right algorithm becomes more complicated : it must avoid to store unused values.

How to find statistical mode in Fortran

I'm trying to write a program to find the mean, median, mode of an integer array but am having some complications in finding the mode. The following is the code that I've written so far.
First, the program will prompt user to enter a value for the number of integers that will be entered followed by request to enter that number of integers. The integers are then sorted in ascending order and the mean and median are found.
The problem I am having is when I try to get the mode. I am able to count the number of occurrence of a repetitive value. By finding the value with highest occurrence, we'll be able to find Mode. But I am unsure how to do this. Is there any intrinsic function in Fortran to calculate number of occurrence of input values and the value with highest occurrence?
PROGRAM STATISTICS
!Created by : Rethnaraj Rambabu
IMPLICIT NONE
REAL, DIMENSION(:), ALLOCATABLE:: VAL
REAL TEMP, MEDIAN
REAL EVEN, MEAN, SUM, FMODE
INTEGER N, I,J
WRITE(*,*)' WHAT IS THE VALUE FOR N? '
READ(*,*) N
ALLOCATE(VAL(N))
WRITE(*,*) 'ENTER THE NUMBERS'
OPEN(1,FILE='FILE.TXT')
READ(1,*)(VAL(I),I=1,N)
CLOSE(1)
WRITE(*,*) VAL
!/---FOR SORTING----/!
DO I=1,N-1
DO J=1,N-1
IF(VAL(J) > VAL(J+1)) THEN
TEMP=VAL(J)
VAL(J)=VAL(J+1)
VAL(J+1)=TEMP
END IF
END DO
END DO
WRITE(*,*) VAL
!/-----MEDIAN----/!
IF ((N/2*2) /= N) THEN
MEDIAN=VAL((N+1)/2)
ELSE IF ((N/2*2) == N) THEN
EVEN= (VAL(N/2)+VAL((N+2)/2))
MEDIAN=EVEN/2
END IF
WRITE(*,*)'MEDIAN=', MEDIAN
!/----MEAN----/
SUM=0
DO I=1,N
SUM=SUM+VAL(I)
END DO
MEAN=SUM/N
WRITE(*,*)'MEAN=', MEAN
!/------MODE----/
FMODE=1
DO I=1,N-1
IF (VAL(I) == VAL(I+1)) THEN
FMODE=FMODE+1
END IF
END DO
WRITE(*,*)FMODE
END PROGRAM
The FILE.TXT contains
10 8 1 9 8 9 9 7 5 9 3 5 6
But, how to do that? Or is there any intrinsic function in Fortran to calculate number of occurrence of input values and the value with highest occurrence.
No, there is not. You'll have to calculate the mode by hand.
The following code should work (on a sorted array):
FMODE = VAL(1)
COUNT = 1
CURRENTCOUNT = 1
DO I = 2, N
! We are going through the loop looking for values == VAL(I-1)...
IF (VAL(I) == VAL(I-1)) THEN
! We spotted another VAL(I-1), so increment the count.
CURRENTCOUNT = CURRENTCOUNT + 1
ELSE
! There are no more VAL(I-1)
IF (CURRENTCOUNT > COUNT) THEN
! There were more elements of value VAL(I-1) than of value FMODE
COUNT = CURRENTCOUNT
FMODE = VAL(I-1)
END IF
! Next we are looking for values == VAL(I), so far we have spotted one...
CURRENTCOUNT = 1
END
END DO
IF (CURRENTCOUNT > COUNT) THEN
! This means there are more elements of value VAL(N) than of value FMODE.
FMODE = VAL(N)
END IF
Explanation:
We keep the best-so-far mode in the FMODE variable, and the count of the FMODE in the COUNT variable. As we step through the array we count the number of hits that are equal to what we are looking at now, in the CURRENTCOUNT variable.
If the next item we look at is equal to the previous, we simply increment the CURRENTCOUNT. If it's different, then we need to reset the CURRENTCOUNT, because we will now count the number of duplications of the next element.
Before we reset the CURRENTCOUNT we check if it's bigger than the previous best result, and if it is, we overwrite the previous best result (the FMODE and COUNT variables) with the new best results (whatever is at VAL(I) and CURRENTCOUNT), before we continue.
This reset doesn't happen at the end of the loop, so I inserted another check at the end in case the most frequent element happens to be the final element of the loop. In that case we overwrite FMODE, like we would have done in the loop.
It is a bit lengthy, you could probably get rid of the optional argument, but there is an example provided here. They use the quick sort algorithm as implemented here.
Alternatively, you could use
integer function mode(arr) result(m)
implicit none
integer, dimension(:), intent(in) :: arr
! Local variables
integer, dimension(:), allocatable :: counts
integer :: i, astat
character(len=128) :: error_str
! Initialise array to count occurrences of each value.
allocate(counts(minval(arr):maxval(arr)), stat=astat, errmsg=error_str)
if (astat/=0) then
print'("Allocation of counts array failed.")'
print*, error_str
end if
counts = 0
! Loop over inputted array, counting occurrence of each value.
do i=1,size(arr)
counts(arr(i)) = counts(arr(i)) + 1
end do
! Finally, find the mode
m = minloc(abs(counts - maxval(counts)),1)
end function mode
This doesn't require any sorting.