Fortran returns NaN, calculate pi - fortran

I created several programs in different languages to calculate pi using trapezoidal sums (C, Perl, and Python similar loops different results) and now I am trying to write one in Fortran. I don't know anything about the language and I wrote this:
program cpi
double precision n, val, pi
integer i, num
n = 1000
num = 1000
val = 0
do i = 1, num
val = val + ((1 - (i ** 2)) ** 0.5)
end do
pi = (2 / n)*(1 + (2 * val))
print *, pi
end program cpi
It returns NaN when I compile it with gfortran and run it. What does this mean and how can I change it to make it work? The C program I want to compare it to is this:
#include <stdio.h>
#include <math.h>
double n = 1000, a, h = 0, t, val, pi;
int main(void)
{
for(a = 1; a < n; ++a) {
t = a/n;
val = pow(1.0-(t*t), 0.5);
h+=val;
}
h = h*2.0;
pi = (2.0/n)*(1.0+h);
printf("%.20f\n", pi);
return 0;
}
Any input on fixing the Fortran program would be very nice.

Thank you to #chux, the program works now:
program cpi
double precision n, val, pi
integer i, num
n = 1000
num = 1000
val = 0
do i = 1, num
val = val + ((1 - ((i / n) ** 2)) ** 0.5)
end do
pi = (2 / n)*(1 + (2 * val))
print *, pi
end program cpi

Related

Calculate integral using rectangle method in Pascal gives 0 while in C++ good results

I'm trying to implement the rectangle method in Pascal. The point is, I'm getting wrong results. I'm getting 0, while the same code in C++ gives me good results. Why is that? Thanks.
Pascal:
Program HelloWorld(output);
function degrees2radians(x: real) : real;
var
result: real;
begin
result := x * 3.14159 / 180.0;
end;
function fun1(x: real) : real;
var
result: real;
begin
x := degrees2radians(x);
result := Sin(x);
end;
function rect_method(a: real; b: real; n: integer) : real;
var
result: real;
h: real;
integral: real;
i : integer;
begin
integral := 0;
i := 0;
h := (a - b) / n;
for i := 1 to n do
begin
integral := integral + fun1(b + i*h)*h;
end;
result := integral;
end;
var
result: real;
begin
result := rect_method(1.0, -2.0, 3);
writeln('result = ', result);
end.
And C++ (which works: https://onlinegdb.com/ubuNQInB2):
#include <iostream>
#include <cstdlib>
#include <cmath>
double degrees2radians(double x)
{
return x * 3.14159 / 180;
}
double f1(double x)
{
x = degrees2radians(x);
return sin(x);
}
double rectangle_method(double a, double b, int n)
{
float h, integral = 0;
h = (a - b) / (double) n;
for (int i=1; i<=n; i++)
integral += f1(b + i*h)*h;
return integral;
}
int main()
{
std::cout << rectangle_method(1, -2, 3) << "\n";
return 0;
}
In your Pascal code result is a local variable, which has nothing to do with the special identifier called result that you want to use:
function degrees2radians(x: real) : real;
var
result: real;
begin
result := x * 3.14159 / 180.0;
end;
You should remove result: real; in all your functions.
However, "fixed" code produces zero anyway: https://onlinegdb.com/_M2pGk134, which is actually correct. That is, this code should return zero.
I rewrote this code in Julia (the language doesn't matter, the point is that it supports high-precision floating-point types out of the box; BigFloat is such a high-precision float), and the result is still zero:
degrees2radians(x::Real)::Real = x * 3.14159 / 180
f1(x::Real) = sin(degrees2radians(x))
function rectangle_method(a::Real, b::Real, n::Integer)
integral = 0
h = (a - b) / n;
for i in 1:n
#show i f1(b + i*h)*h
integral += f1(b + i*h)*h;
end
return integral;
end
#show rectangle_method(BigFloat("1"), -BigFloat("2"), 3)
The output looks like this:
i = 1
f1(b + i * h) * h = -0.01745239169736329549313317881927049082689975241899824937795751704833664190229729
i = 2
f1(b + i * h) * h = 0.0
i = 3
f1(b + i * h) * h = 0.01745239169736329549313317881927049082689975241899824937795751704833664190229729
rectangle_method(BigFloat("1"), -(BigFloat("2")), 3) = 0.0
So, f1(b + 2 * h) * h is zero, and f1(b + 1 * h) * h is exactly (look at the amount of digits after the decimal point!) the negative of f1(b + 3 * h) * h, so they cancel out in the integral sum, resulting in zero.

Fast SSE low precision exponential using double precision operations

I am looking for for a fast-SSE-low-precision (~1e-3) exponential function.
I came across this great answer:
/* max. rel. error = 3.55959567e-2 on [-87.33654, 88.72283] */
__m128 FastExpSse (__m128 x)
{
__m128 a = _mm_set1_ps (12102203.0f); /* (1 << 23) / log(2) */
__m128i b = _mm_set1_epi32 (127 * (1 << 23) - 298765);
__m128i t = _mm_add_epi32 (_mm_cvtps_epi32 (_mm_mul_ps (a, x)), b);
return _mm_castsi128_ps (t);
}
Based on the work of Nicol N. Schraudolph: N. N. Schraudolph. "A fast, compact approximation of the exponential function." Neural Computation, 11(4), May 1999, pp.853-862.
Now I would need a "double precision" version: __m128d FastExpSSE (__m128d x).
This is because I don't control the input and output precision, which happen to be double precision, and the two conversions double -> float, then float -> double is eating 50% of the CPU resources.
What changes would be needed?
I naively tried this:
__m128i double_to_uint64(__m128d x) {
x = _mm_add_pd(x, _mm_set1_pd(0x0010000000000000));
return _mm_xor_si128(
_mm_castpd_si128(x),
_mm_castpd_si128(_mm_set1_pd(0x0010000000000000))
);
}
__m128d FastExpSseDouble(__m128d x) {
#define S 52
#define C (1llu << S) / log(2)
__m128d a = _mm_set1_pd(C); /* (1 << 52) / log(2) */
__m128i b = _mm_set1_epi64x(127 * (1llu << S) - 298765llu << 29);
auto y = double_to_uint64(_mm_mul_pd(a, x));
__m128i t = _mm_add_epi64(y, b);
return _mm_castsi128_pd(t);
}
Of course this returns garbage as I don't know what I'm doing...
edit:
About the 50% factor, it is a very rough estimation, comparing the speedup (with respect to std::exp) converting a vector of single precision numbers (great) to the speedup with a list of double precision numbers (not so great).
Here is the code I used:
// gives the result in place
void FastExpSseVector(std::vector<double> & v) { //vector with several millions elements
const auto I = v.size();
const auto N = (I / 4) * 4;
for (int n = 0; n < N; n += 4) {
float a[4] = { float(v[n]), float(v[n + 1]), float(v[n + 2]), float(v[n + 3]) };
__m128 x;
x = _mm_load_ps(a);
auto r = FastExpSse(x);
_mm_store_ps(a, r);
v[n] = a[0];
v[n + 1] = a[1];
v[n + 2] = a[2];
v[n + 3] = a[3];
}
for (int n = N; n < I; ++n) {
v[n] = FastExp(v[n]);
}
}
And here is what I would do if I had this "double precision" version:
void FastExpSseVectorDouble(std::vector<double> & v) {
const auto I = v.size();
const auto N = (I / 2) * 2;
for (int n = 0; n < N; n += 2) {
__m128d x;
x = _mm_load_pd(&v[n]);
auto r = FastExpSseDouble(x);
_mm_store_pd(&v[n], r);
}
for (int n = N; n < I; ++n) {
v[n] = FastExp(v[n]);
}
}
Something like this should do the job. You need to tune the 1.05 constant to get a lower maximal error -- I'm too lazy to do that:
__m128d fastexp(const __m128d &x)
{
__m128d scaled = _mm_add_pd(_mm_mul_pd(x, _mm_set1_pd(1.0/std::log(2.0)) ), _mm_set1_pd(3*1024.0-1.05));
return _mm_castsi128_pd(_mm_slli_epi64(_mm_castpd_si128(scaled), 11));
}
This just gets about 2.5% relative precision -- for better precision you may need to add a second term.
Also, for values which overflow or underflow this will result in unspecified values, you can avoid this by clamping the scaled value to some values.

C++ Theta function implementation

I am trying to implement this function:
but it's not working. A minimal, verifiable example looks like:
#include <iostream>
#include <cmath>
int main()
{
int N {8}; // change this for testing <1..inf>
double q {0.1 / N};
int countN {static_cast<int>(floor(N / 2))};
static const double PI {3.1415926535897932384626433832795};
// Omega[i] = Theta1(u,m) / Theta4(u,m)
double Omega[countN];
for (int i=0; i<countN; ++i)
{
double micro {!(N % 2) * 0.5}; // 0 for odd N, 1/2 for even N
double num[countN] {sin(PI / N * (i + 1 - micro))};
double den[countN] {0.5};
for (int m=1; m<4; ++m)
{
num[i] += pow(-1, m) * pow(q, m*(m + 1)) * sin((2 * m + 1) * PI / N * (i + 1 - micro));
den[i] += pow(-1, m) * pow(q, m*m) * cos(2 * m * PI / N * (i + 1 - micro));
}
Omega[i] = fabs(pow(q, 0.25) * num[i] / den[i]);
std::cout << " " << Omega[i] << "\n";
}
// testing the values, they should be increasing in value
for (const auto &elem: Omega)
std::cout << elem << " ";
std::cout << "\n";
return 0;
}
There is a minor simplification compared to the original: I factored 2 in both numerator and denominator and I used only the q^0.25 outside of the fraction. Also, countN is the r from the original document, micro is only the 1/2 for even N or 0 for odd N, and i is 0 for array's index but i+1 for calculations, but these shouldn't matter overall.
I tried this with wxMaxima:
Theta[1](x,y):=2*y^0.25*sum( (-1)^k*y^(k*(k+1))*sin((2*k+1)*x),k,0,n );
Theta[4](x,y):=1+2*sum( (-1)^k*y^(k^2)*cos(2*k*x),k,1,n );
n:4$
N:8$
a:0.05$
b(i):=%pi/N*(i-(1-mod(N,2))/2)$
for N:8 thru 9 do for i:1 thru N/2 do print(["N=",N,"i=",i],Theta[1](b(i),a)/Theta[4](b(i),a)),numer;
And the results, in C++:
(q=0.05; N=8)
Omega[0]=0.2018370065366672
Omega[1]=0.06058232646142273
Omega[2]=0.01205653570636574
Omega[3]=0.02127667733703158
(q=0.05; N=9)
Omega[0]=0.348078726440638
Omega[1]=0.1178366281313341
Omega[2]=2.559808325080287e-07
Omega[3]=0.02178788541277828
and in wxMaxima:
["N=",8,"i=",1]" "0.2018370065366672" "
["N=",8,"i=",2]" "0.5439269564954693" "
["N=",8,"i=",3]" "0.7569342043740249" "
["N=",8,"i=",4]" "0.850913653939989" "
["N=",9,"i=",1]" "0.348078726440638" "
["N=",9,"i=",2]" "0.6165773889432575" "
["N=",9,"i=",3]" "0.7800391631077094" "
["N=",9,"i=",4]" "0.8532352152763631
To my surprise, the first term is good, for bith N, so I can't tell what in my code is not right. Could someone help me spot the error?
To be clear about it: I am a beginner in C++ and I am not looking for someone to do it for me, but to let me know of my erros in coding (translating math to C++ code).
You had
double den[countN] {0.5};
this initializes the first element of den to 0.5 and all the other elements to 0.0 (default initialization). In other words, the above is equivalent to
double den[countN] {0.5, 0.0, 0.0, 0.0};
with as many zeros as necessary to fill the array. You probably wanted to initialize all the elements to 0.5. In your case, the easiest way to do that is when you first use that element - or, since you access only the single element den[i] during the lifetime of den, make it a plain double rather than an array:
for (int i=0; i<countN; ++i) {
double micro {N % 2 ? 0.0 : 0.5}; // 0 for odd N, 1/2 for even N
double num{sin(PI / N * (i + 1 - micro))};
double den{0.5};
for (int m=1; m<4; ++m) {
num += pow(-1, m) * pow(q, m*(m + 1)) * sin((2 * m + 1) * PI / N * (i + 1 - micro));
den += pow(-1, m) * pow(q, m*m) * cos(2 * m * PI / N * (i + 1 - micro));
}
Omega[i] = fabs(pow(q, 0.25) * num / den);
}

pseudo code for sqrt function

I managed to get my sqrt function to run perfectly, but I'm second guessing if I wrote this code correctly based on the pseudo code I was given.
Here is the pseudo code:
x = 1
repeat 10 times: x = (x + n / x) / 2
return x.
The code I wrote,
#include <iostream>
#include <math.h>
using namespace std;
double my_sqrt_1(double n)
{
double x= 1; x<10; ++x;
return (x+n/x)/2;
}
No, your code is not following your pseudo-code. For example, you're not repeating anything in your code. You need to add a loop to do that:
#include <iostream>
#include <math.h>
using namespace std;
double my_sqrt_1(double n)
{
double x = 1;
for(int i = 0; i < 10; ++i) // repeat 10 times
x = (x+n/x)/2;
return x;
}
Let's analyze your code:
double x = 1;
// Ok, x set to 1
x < 10;
// This is true, as 1 is less than 10, but it is not used anywhere
++x;
// Increment x - now x == 2
return (x + n / x) / 2
// return value is always (2 + n / 2) / 2
As you don't have any loop, function will always exit in the first "iteration" with the return value (2 + n / 2) / 2.
Just as another approach that you can use binary search or the another pretty elegant solution is to use the Newton's method.
Newton's method is a method for finding roots of a function, making use of a function's derivative. At each step, a value is calculated as: x(step) = x(step-1) - f(x(step-1))/f'(x(step-1)) Newton's_method
This might be faster than binary search.My implementation in C++:
double NewtonMethod(double x) {
double eps = 0.0001; //the precision
double x0 = 10;
while( fabs(x-x0) > eps) {
double a = x0*x0-n;
double r = a/(2*x0);
x = x0 - r;
x0 = x;
}
return x;
}
Since people are showing different approaches to calculating the square root, I couldn't resist ;)...
Below is the exact copy (with the original comments, but without preprocessor directives) of the inverse square root implementation from Quake III Arena:
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the...?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}

find as many digits of the square root of 2 as possible

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double a = sqrt(2);
cout << a << endl;
}
hi this is the program to find sqrt of 2 it prints just 1.41421 in the output how to implement it in way such that it will print 200000 digits after decimal point
1.41421..........upto 200 000 digits
Is there any approach to print like this?
It can be shown that
sqrt(2) = (239/169)*1/sqrt(1-1/57122)
And 1/sqrt(1-1/57122) can be computed efficiently using the Taylor series expansion:
1/sqrt(1-x) = 1 + (1/2)x + (1.3)/(2.4)x^2 + (1.3.5)/(2.4.6)x^3 + ...
There's also a C program available that uses this method (I've slightly reformatted and corrected it):
/*
** Pascal Sebah : July 1999
**
** Subject:
**
** A very easy program to compute sqrt(2) with many digits.
** No optimisations, no tricks, just a basic program to learn how
** to compute in multiprecision.
**
** Formula:
**
** sqrt(2) = (239/169)*1/sqrt(1-1/57122)
**
** Data:
**
** A big real (or multiprecision real) is defined in base B as:
** X = x(0) + x(1)/B^1 + ... + x(n-1)/B^(n-1)
** where 0<=x(i)<B
**
** Results: (PentiumII, 450Mhz)
**
** 1000 decimals : 0.02seconds
** 10000 decimals : 1.7s
** 100000 decimals : 176.0s
**
** With a little work it's possible to reduce those computation
** times by a factor of 3 and more.
*/
#include <stdio.h>
#include <stdlib.h>
long B = 10000; /* Working base */
long LB = 4; /* Log10(base) */
/*
** Set the big real x to the small integer Integer
*/
void SetToInteger(long n, long* x, long Integer)
{
long i;
for (i = 1; i < n; i++)
x[i] = 0;
x[0] = Integer;
}
/*
** Is the big real x equal to zero ?
*/
long IsZero(long n, long* x)
{
long i;
for (i = 0; i < n; i++)
if (x[i])
return 0;
return 1;
}
/*
** Addition of big reals : x += y
** Like school addition with carry management
*/
void Add(long n, long* x, long* y)
{
long carry = 0, i;
for (i = n - 1; i >= 0; i--)
{
x[i] += y[i] + carry;
if (x[i] < B)
carry = 0;
else
{
carry = 1;
x[i] -= B;
}
}
}
/*
** Multiplication of the big real x by the integer q
*/
void Mul(long n, long* x, long q)
{
long carry = 0, xi, i;
for (i = n - 1; i >= 0; i--)
{
xi = x[i] * q;
xi += carry;
if (xi >= B)
{
carry = xi / B;
xi -= carry * B;
}
else
carry = 0;
x[i] = xi;
}
}
/*
** Division of the big real x by the integer d
** Like school division with carry management
*/
void Div(long n, long* x, long d)
{
long carry = 0, xi, q, i;
for (i = 0; i < n; i++)
{
xi = x[i] + carry * B;
q = xi / d;
carry = xi - q * d;
x[i] = q;
}
}
/*
** Print the big real x
*/
void Print(long n, long* x)
{
long i;
printf("%ld.", x[0]);
for (i = 1; i < n; i++)
printf("%04ld", x[i]);
printf("\n");
}
/*
** Computation of the constant sqrt(2)
*/
int main(void)
{
long NbDigits = 200000, size = 1 + NbDigits / LB;
long* r2 = malloc(size * sizeof(long));
long* uk = malloc(size * sizeof(long));
long k = 1;
/*
** Formula used:
** sqrt(2) = (239/169)*1/sqrt(1-1/57122)
** and
** 1/sqrt(1-x) = 1+(1/2)x+(1.3)/(2.4)x^2+(1.3.5)/(2.4.6)x^3+...
*/
SetToInteger(size, r2, 1); /* r2 = 1 */
SetToInteger(size, uk, 1); /* uk = 1 */
while (!IsZero(size, uk))
{
Div(size, uk, 57122); /* uk = u(k-1)/57122 * (2k-1)/(2k) */
Div(size, uk, 2 * k);
Mul(size, uk, 2 * k - 1);
Add(size, r2, uk); /* r2 = r2+uk */
k++;
}
Mul(size, r2, 239);
Div(size, r2, 169); /* r2 = (239/169)*r2 */
Print(size, r2); /* Print out of sqrt(2) */
free(r2);
free(uk);
return 0;
}
It takes about a minute to calculate 200,000 digits of sqrt(2).
Note, however, at 200,000 digits the last 11 digits produced are incorrect due to the accumulated rounding errors and you need to run it for 200,012 digits if you want 200,000 correct digits.
Here is the code for your question which using GNU GMP library. The code will print 1000 digits of sqrt(2), increase the number in the lines with comment to satisfy your request.
#include <stdio.h>
#include <gmp.h>
int main(int argc, char *argv[])
{
mpf_t res,two;
mpf_set_default_prec(1000000); // Increase this number.
mpf_init(res);
mpf_init(two);
mpf_set_str(two, "2", 10);
mpf_sqrt (res, two);
gmp_printf("%.1000Ff\n\n", res); // increase this number.
return 0;
}
Please compile it with the following command:
$gcc gmp.c -lgmp -lm -O0 -g3
Here is a solution that computes 1 million digits of sqrt(2) in less than a minute in the good old Prolog programming language. It is based on solving the pell equation, see also here:
p*p+1 = 2*q*q
The recurence relation p′=3p+4q and q′=2p+3q can be cast as a matrix multiplication. Namely we see that if we multiply the vector [p,q] by the matrix of the coefficients we get the vector [p',q']:
| p' | | 3 4 | | p |
| | = | | * | |
| q' | | 2 3 | | q |
For matrix A we can use a binary recursion so that we can calculate A^n in O(log n) operations. We will need big nums. I am using this experimental code here whereby the main program is then simply:
/**
* pell(N, R):
* Compute the N-the solution to p*p+1=2*q*q via matrices and return
* p/q in decimal format in R.
*/
pell(N, R) :-
X is [[3,4],[2,3]],
Y is X^N,
Z is Y*[[1],[1]],
R is Z[1,1]*10^N//Z[2,1].
The following screenshot shows the timing and some results. I was using 10-times a million iterations. One can compare the result with this page here.
Whats missing is still a clear cut criteria and computation that says how many digits are stable. We will need some more time to do that.
Edit 20.12.2016:
We improved the code a little bit by an upper bound of the relative error, and further compute stable digits by nudging the result. The computation time for 1 million digits is now below 2 secs:
?- time(pell(653124, _, S)).
% Uptime 1,646 ms, GC Time 30 ms, Thread Cpu Time 1,640 ms
S = -1000000
The example you give is accurate in so far as the precision of double arithmetic goes, this is the highest precision most C++ compilers use. In general computers are not tooled to do higher precision calculation.
If this is homework of some sort then I suspect you are required to figure out an algorithm for calculating - you need to keep you own array of digits in some way to keep all the precision that you need.
If you have some real-world application you should definitely use a high precision library specifically made to do this sort of arithmetic (GMP is a good open-source possibility) - this is a complicated wheel that doesn't need reinventing.
This following Javascript function will take an integer and the digits of /precision required after the decimal, then return a string format of the square root.
// Input: a positive integer, the number of precise digits after the decimal point
// Output: a string representing the long float square root
function findSquareRoot(number, numDigits) {
function get_power(x, y) {
let result = 1n;
for (let i = 0; i < y; i ++) {
result = result * BigInt(x);
}
return result;
}
let a = 5n * BigInt(number);
let b = 5n;
const precision_digits = get_power(10, numDigits + 1);
while (b < precision_digits) {
if (a >= b) {
a = a - b;
b = b + 10n;
} else {
a = a * 100n;
b = (b / 10n) * 100n + 5n;
}
}
let decimal_pos = Math.floor(Math.log10(number))
if (decimal_pos == 0) decimal_pos = 1
let result = (b / 100n).toString()
result = result.slice(0, decimal_pos) + '.' + result.slice(decimal_pos)
return result
}