Program to calculate sin(0.75) close, but not working? - fortran

I have already posted a question regarding this problem, and have implemented what i've learned from the answers. I'm now at a point where the answers that are printed out on the screen are very close, but incorrect. Here is the code I now have:
program taylor
implicit none
integer :: k = 0
real :: y = 0.75
real :: x = 0.75
do while (abs(y - sin(0.75)) > 1E-6)
k = k + 1
y = y + ((y * (-x * x)) /( 2 * k * (2 * k + 1 )))
print *, y
end do
end program taylor
I can't seem to spot the error here, why is this not working? The first answer it prints is correct, but then it seems to get progressively lower, instead of closer to the true value. (The do while loop is to ensure the program stops when the absolute value between the calculation and the intrinsic sin function is less than 1E-6). I can see that the program is constantly reducing the final output, and the Taylor series is suppose to alternate between - and +, so how can I write that in my program?
Thanks.

The taylor series uses factorials and power of x.
taylor_sin(x) = sum[0->n] ( [(-1 ^ n) / (2n + 1)!] * x**(2n + 1) )
(Sorry for my poor keyboard math skills...)
program taylor
implicit none
integer :: n = 0
real :: fac = 1
real :: y = 0.75
real :: x = 0.75
real :: px = 1
integer :: sgn = -1
integer :: s = 1
do while (abs(y - sin(0.75)) > 1E-6)
n = n + 1
fac = fac * (2 * n) * ((2 * n) + 1)
px = px * (x * x)
s = s * sgn
y = y + ((s /fac) * (px * x))
print *, y
end do
end program taylor
Computing the factorial fac in a loop is rather trivial.
To compute x**(2n + 1), compute and keep x**(2n) and add an extra multiplication by x.
I use an integer to compute -1**n since using a real may lose precision over time.
[EDIT] silly me... you can save that extra multiplication by x by setting px to 0.75 before the loop.

Related

How to calculate Pi using Monte Carlo Simulation?

I'm attempting to write a FORTRAN 90 program that calculates Pi using random numbers. These are the steps I know I need to undertake:
Create a randomly placed point on a 2D surface within the range [−1, 1] for x and y, using call random_number(x).
calculate how far away the point is from the origin, i'll need to do both of these steps for N points.
for each N value work out the total amount of points that are less than 1 away from origin. Calculate pi with A=4pir^2
use a do loop to calculate pi as a function of N and output it to a data file. then plot it in a graphing package.
This is what I have:
program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
END DO
r = 4 * REAL(count)/n
print *, r
end program pi
I know i've missed out printing the results to the data file, i'm not sure on how to implement this.
This program gives me a nice value for pi (3.149..), but how can I implement step 4, so that it outputs values for pi as a function of N?
Thanks.
Here is an attempt to further #meowgoesthedog effort...
Program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
Integer, parameter :: Slice_o_Pie = 8
Integer :: Don_McLean
Logical :: Purr = .FALSE.
OPEN(NEWUNIT=Don_McLean, FILE='American.Pie')
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
Purr = .FALSE.
IF(MODULO(I, Slice_o_Pie) == 0) Purr = .TRUE.
IF (Purr) THEN
r = 4 * REAL(count)/i
print *, i, r
WRITE(LUN,*) 'I=',I,'Pi=',Pi
END IF
END DO
CLOSE(Don_McLean)
end program pi
Simply put the final calculation step inside the outer loop, and replace n with i. Also maybe add a condition to limit the number of results printed, e.g. i % 100 = 0 to print every 100 iterations.
program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
IF ([condition])
r = 4 * REAL(count)/i
print *, i, r
END IF
END DO
end program pi

Program For Calculating Sin Using Taylor Expansion Not Working?

I'm trying to write some code that'll calculate the value of sin(0.75) using the Taylor expansion, and print each iteration until the absolute difference between the value calculated using the expansion, and the value calculated using Fortran's intrinsic sin function is less than 1E-6. Here is my code:
program taylor
implicit none
real :: x = 0.75
do while (x - sin(0.75) < 10**(-6))
print *, x
x = x - ((x**3)/6) + ((x**5)/120) - ((x**7)/5040)
end do
end program taylor
However, this doesn't print anything out? Why is this?
It looks too obvious to most people so no-one even wanted to answer, but it should be said explicitly
The condition x - sin(0.75) < 10**(-6) is obviously not true when x very different from sin(0.75), so the do while loop is never entered.
Also, as IanH commented 10**(-6) will give 0 because the result of the power of two integers is again an integer. The literal real number 10^-6 should be expressed as 1e-6.
If you change it to x - sin(0.75) > 1e-6 the loop will proceed, but it will run forever, because your iteration is wrong. Taylor series works differently, you should compute
y = 0
y = y + x**1/1!
y = y - x**3/3!
y = y + x**5/5!
y = y - x**7/7!
...
and so on, which is a very different kind of loop.
Try this one:
program taylor
implicit none
real :: x = 0.75
real :: y, fact
integer :: sgn, i
fact = 1
sgn = 1
y = 0
do i = 1, 10, 2
y = y + sgn * x**i / fact
fact = fact*(i+1)*(i+2)
sgn = -sgn
end do
print *, y, sin(x)
end program taylor

Using series to approximate log(2)

double k = 0;
int l = 1;
double digits = pow(0.1, 5);
do
{
k += (pow(-1, l - 1)/l);
l++;
} while((log(2)-k)>=digits);
I'm trying to write a little program based on an example I seen using a series of Σ_(l=1) (pow(-1, l - 1)/l) to estimate log(2);
It's supposed to be a guess refinement thing where time it gets closer and closer to the right value until so many digits match.
The above is what I tried but but it's not coming out right. After messing with it for quite a while I can't figure out where I'm messing up.
I assume that you are trying to extimate the natural logarithm of 2 by its Taylor series expansion:
∞ (-1)n + 1
ln(x) = ∑ ――――――――(x - 1)n
n=1 n
One of the problems of your code is the condition choosen to stop the iterations at a specified precision:
do { ... } while((log(2)-k)>=digits);
Besides using log(2) directly (aren't you supposed to find it out instead of using a library function?), at the second iteration (and for every other even iteration) log(2) - k gets negative (-0.3068...) ending the loop.
A possible (but not optimal) fix could be to use std::abs(log(2) - k) instead, or to end the loop when the absolute value of 1.0 / l (which is the difference between two consecutive iterations) is small enough.
Also, using pow(-1, l - 1) to calculate the sequence 1, -1, 1, -1, ... Is really a waste, especially in a series with such a slow convergence rate.
A more efficient series (see here) is:
∞ 1
ln(x) = 2 ∑ ――――――― ((x - 1) / (x + 1))2n + 1
n=0 2n + 1
You can extimate it without using pow:
double x = 2.0; // I want to calculate ln(2)
int n = 1;
double eps = 0.00001,
kpow = (x - 1.0) / (x + 1.0),
kpow2 = kpow * kpow,
dk,
k = 2 * kpow;
do {
n += 2;
kpow *= kpow2;
dk = 2 * kpow / n;
k += dk;
} while ( std::abs(dk) >= eps );

Calculating Sin(x) using Fortran

integer n
real term , sum , deg
write(*,*) 'Enter Degree'
read(*,*) deg
deg = deg * 3.14 /180
n = 3
term = deg
sum = 0
2 if ( abs(term) .gt. 0.000001) then !<<<<<<<<<<< THIS CONDITION
goto 1
else
goto 3
endif
1 sum = sum + term
write( *,*) 'Your', n - 2, ' Term is ' , term
term = term *(( deg ** 2)/ (n *( n - 1))) * (-1)
n = n + 2
goto 2
3 write(*,*) ' YOur final sum ' , sum
pause
end
I found this program for the calculating Sin(x) It is clear the The value of sin(x) is entered by User by I didn't get the whole point of condition ( abs(term) .gt. 0.000001) Does this mean that the computer can't be more precise than this. correct me if I am wrong
This program uses default real variables. They usually allow to precision of approx. 6 digits. You can use the so called double precision which can allow more. Below you see example for 15 digits.
integer,parameter :: dp = selected_real_kind(p=15,r=200)
real(dp) :: term , sum , deg
deg = deg * 3.14_dp /180
and so on...
See:
http://gcc.gnu.org/onlinedocs/gfortran/SELECTED_005fREAL_005fKIND.html
http://gcc.gnu.org/onlinedocs/gfortran/ISO_005fFORTRAN_005fENV.html (especially real64)
In old programs you can also see
double precision x
which is obsolete, or
real*8 x
which is nonstandard.
The condition if ( abs(term) .gt. 0.000001) is a way of testing that the term is non-zero. With integers, you would just use if (term .ne. 0), but for real numbers it might not be represented as identically zero internally. if ( abs(term) .gt. 0.000001) filters numbers that are non-zero within the precision of the real number.

What is the Basic Structure of a Function in FORTRAN?

This is something that's I've wanted to know recently, mostly out of curiousity. I'm in the mood to learn some old coding styles, and FORTRAN seems like a good place to start.
I guess I should help you guys out by providing a good starting point.
So how would this C procedure be written in FORTRAN?
int foo ( int x , int y )
{
int tempX = x ;
x += y / 2 ;
y -= tempX * 3 ; // tempX holds x's original value.
return x * y ;
}
I know the entire function could be a single line:
return ( x + ( y / 2 ) ) * ( y - ( x * 3 ) ) ;
But the point of me asking this question is to see how those four statements would be written individually in FORTRAN, not neccessarily combined into a single statement.
Don't blame me - you said old coding styles:
C234567
SUBROUTINE FOO(I,J,K)
C SAVE THE ORIGINAL VALUES
IORIG = I
JORIG = J
C PERFORM THE COMPUTATION
I = I + J/2
J = J - IORIG*3
K = I * J
C RESTORE VALUES
I = IORIG
J = JORIG
END SUBROUTINE FOO
I shudder as I write this, but
all variables are implicitly integers, since they start with letters between I and N
FORTRAN passes by reference, so reset I and J at the end to give the same effect as the original function (i.e. pass-by-value, so x and y were unchanged in the calling routine)
Comments start in column 1, actual statements start in column 7
Please, please, please never write new code like this unless as a joke.
Your function might look like this in Fortran
integer function foo(m, n)
integer i
i = m
m = m + n/2
n = n - i*3
foo = m*n
end function foo
You should be able to get started with any tutorial on Fortran. Some thing like this might help http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/fortran.html
cheers
See Functions and Subroutines:
INTEGER FUNCTION foo(i, j)
...
foo = 42
END
then later:
k = foo(1, 2)
Where do you learn FORTRAN from? Just take a look at the wikibooks!
Derived from the example, I'd say:
function func(x, y) result(r)
integer, intent(in) :: x, y
integer :: r
integer :: tempX
tempX = x
x = x / 2
y = y - tempX * 3
r = x * y
end function foo
Similar to above, but with a main program to illustrate how it would be called.
C2345678
program testfoo
implicit none
integer r, foo
r = foo(4,5)
print *, 'result = ', r
end
integer function foo(x,y)
integer x, y
integer tx, ty
tx = x + y / 2
ty = y - x * 3
foo = tx * ty
return
end
Note that this is Fortran 77, which is what I learned 23 years ago.
True old style in applying the rule IJKLMN for integer
C2345678
FUNCTION IFOO(I,J)
II = I + J/2
JJ = J - I*3
IFOO = II*JJ
END