I need to check if the imaginary part is very small and set it to zero if it is in order to eliminate some floating point errors that result in very small non-zero imaginary parts when it should be zero.
My code is as follows:
kz2 = SQRT((n2*(2.0*PI*eta))**2 - kxarray(p)**2)
kz1 = SQRT((n1*(2.0*PI*eta))**2 - kxarray(p)**2)
if (aimag(kz2) < 0.0005) then
kz2 = (REAL(kz2),0.0)
end if
if (aimag(kz1) < 0.0005) then
kz1 = (REAL(kz1), 0.0)
end if
Unfortunately the compiler just returns:
gaussian1.f90:122.18:
kz2 = (REAL(kz2),0.0)
1
Error: Expected a right parenthesis in expression at (1)
gaussian1.f90:126.18:
kz1 = (REAL(kz1), 0.0)
1
Error: Expected a right parenthesis in expression at (1)
Any advice would be greatly appreciated - am I even going about this problem the right way?
UPDATE: I managed to avoid the problem by using:
if (aimag(kz2) < 0.0005) then
kz2 = real(kz2)
end if
if (aimag(kz1) < 0.0005) then
kz1 = real(kz1)
end if
But what would I do if I wanted to set the imaginary part to a non-zero amount?
In Fortran 2008 there are even more possibilities. You can access real and imaginary parts as derived type components, e.g.
a = c%re
b%im = 5
So, to set imaginary part of z to zero in new compilers you can try z%im = 0 .
I think you are looking for the CMPLX function, which converts real or integer arguments to a complex number. So it you example you should be able to do something like this:
kz1 = cmplx(real(kz1), 0.)
The (1.0,1.0) style parenthesis notation you have tried is only valid for constant values, not forming a complex number from the values held in variables.
I am converting f77 code to f90 code, and part of the code needs to sum over elements of a 3d matrix. In f77 this was accomplished by using 3 loops (over outer,middle,inner indices). I decided to use the f90 intrinsic sum (3 times) to accomplish this, and much to my surprise the answers differ. I am using the ifort compiler, have debugging, check-bounds, no optimization all turned on
Here is the f77-style code
r1 = 0.0
do k=1,nz
do j=1,ny
do i=1,nx
r1 = r1 + foo(i,j,k)
end do
end do
end do
and here is the f90 code
r = SUM(SUM(SUM(foo, DIM=3), DIM=2), DIM=1)
I have tried all sorts of variations, such as swapping the order of the loops for the f77 code, or creating temporary 2D matrices and 1D arrays to "reduce" the dimensions while using SUM, but the explicit f77 style loops always give different answers from the f90+ SUM function.
I'd appreciate any suggestions that help understand the discrepancy.
By the way this is using one serial processor.
Edited 12:13 pm to show complete example
! ifort -check bounds -extend-source 132 -g -traceback -debug inline-debug-info -mkl -o verify verify.f90
! ./verify
program verify
implicit none
integer :: nx,ny,nz
parameter(nx=131,ny=131,nz=131)
integer :: i,j,k
real :: foo(nx,ny,nz)
real :: r0,r1,r2
real :: s0,s1,s2
real :: r2Dfooxy(nx,ny),r1Dfoox(nx)
call random_seed
call random_number(foo)
r0 = 0.0
do k=1,nz
do j=1,ny
do i=1,nx
r0 = r0 + foo(i,j,k)
end do
end do
end do
r1 = 0.0
do i=1,nx
do j=1,ny
do k=1,nz
r1 = r1 + foo(i,j,k)
end do
end do
end do
r2 = 0.0
do j=1,ny
do i=1,nx
do k=1,nz
r2 = r2 + foo(i,j,k)
end do
end do
end do
!*************************
s0 = 0.0
s0 = SUM(SUM(SUM(foo, DIM=3), DIM=2), DIM=1)
s1 = 0.0
r2Dfooxy = SUM(foo, DIM = 3)
r1Dfoox = SUM(r2Dfooxy, DIM = 2)
s1 = SUM(r1Dfoox)
s2 = SUM(foo)
!*************************
print *,'nx,ny,nz = ',nx,ny,nz
print *,'size(foo) = ',size(foo)
write(*,'(A,4(ES15.8))') 'r0,r1,r2 = ',r0,r1,r2
write(*,'(A,3(ES15.8))') 'r0-r1,r0-r2,r1-r2 = ',r0-r1,r0-r2,r1-r2
write(*,'(A,4(ES15.8))') 's0,s1,s2 = ',s0,s1,s2
write(*,'(A,3(ES15.8))') 's0-s1,s0-s2,s1-s2 = ',s0-s1,s0-s2,s1-s2
write(*,'(A,3(ES15.8))') 'r0-s1,r1-s1,r2-s1 = ',r0-s1,r1-s1,r2-s1
stop
end
!**********************************************
sample output
nx,ny,nz = 131 131 131
size(foo) = 2248091
r0,r1,r2 = 1.12398225E+06 1.12399525E+06 1.12397238E+06
r0-r1,r0-r2,r1-r2 = -1.30000000E+01 9.87500000E+00 2.28750000E+01
s0,s1,s2 = 1.12397975E+06 1.12397975E+06 1.12398225E+06
s0-s1,s0-s2,s1-s2 = 0.00000000E+00-2.50000000E+00-2.50000000E+00
r0-s1,r1-s1,r2-s1 = 2.50000000E+00 1.55000000E+01-7.37500000E+00
First, welcome to StackOverflow. Please take the tour! There is a reason we expect a Minimal, Complete, and Verifiable example because we look at your code and can only guess at what might be the case and that is not too helpful for the community.
I hope the following suggestions helps you figure out what is going on.
Use the size() function and print what Fortran thinks are the sizes of the dimensions as well as printing nx, ny, and nz. As far as we know, the array is declared bigger than nx, ny, and nz and these variables are set according to the data set. Fortran does not necessarily initialize arrays to zero depending on whether it is a static or allocatable array.
You can also try specifying array extents in the sum function:
r = Sum(foo(1:nx,1:ny,1:nz))
If done like this, at least we know that the sum function is working on the exact same slice of foo that the loops loop over.
If this is the case, you will get the wrong answer even though there is nothing 'wrong' with the code. This is why it is particularly important to give that Minimal, Complete, and Verifiable example.
I can see the differences now. These are typical rounding errors from adding small numbers to a large sum. The processor is allowed to use any order of the summation it wants. There is no "right" order. You cannot really say that the original loops make the "correct" answer and the others do not.
What you can do is to use double precision. In extreme circumstances there are tricks like the Kahan summation but one rarely needs that.
Addition of a small number to a large sum is imprecise and especially so in single precision. You still have four significant digits in your result.
One typically does not use the DIM= argument, that is used in certain special circumstances.
If you want to sum all elements of foo, use just
s0 = SUM(foo)
That is enough.
What
s0 = SUM(SUM(SUM(foo, DIM=3), DIM=2), DIM=1)
does is that it will make a temporary 2D arrays with each element be the sum of the respective row in the z dimension, then a 1D array with each element the sum over the last dimension of the 2D array and then finally the sum of that 1D array. If it is done well, the final result will be the same, but it well eat a lot of CPU cycles.
The sum intrinsic function returns a processor-dependant approximation to the sum of the elements of the array argument. This is not the same thing as adding sequentially all elements.
It is simple to find an array x where
summation = x(1) + x(2) + x(3)
(performed strictly left to right) is not the best approximation for the sum treating the values as "mathematical reals" rather than floating point numbers.
As a concrete example to look at the nature of the approximation with ifort, we can look at the following program. We need to enable optimizations here to see effects; the importance of order of summation is apparent even with optimizations disabled (with -O0 or -debug).
implicit none
integer i
real x(50)
real total
x = [1.,(EPSILON(0.)/2, i=1, SIZE(x)-1)]
total = 0
do i=1, SIZE(x)
total = total+x(i)
print '(4F17.14)', total, SUM(x(:i)), SUM(DBLE(x(:i))), REAL(SUM(DBLE(x(:i))))
end do
end program
If adding up in strict order we get 1., seeing that anything smaller in magnitude than epsilon(0.) doesn't affect the sum.
You can experiment with the size of the array and order of its elements, the scaling of the small numbers and the ifort floating point compilation options (such as -fp-model strict, -mieee-fp, -pc32). You can also try to find an example like the above using double precision instead of default real.
I am using the following function written in C++, whose purpose is to take the integral of one array of data (y) with respect to another (x)
// Define function to perform numerical integration by the trapezoidal rule
double trapz (double xptr[], double yptr[], int Npoints)
{
// The trapzDiagFile object and associated output file are how I monitor what data the for loop actually sees.
std::ofstream trapzDiagFile;
trapzDiagFile.open("trapzDiagFile.txt",std::ofstream::out | std::ofstream::trunc);
double buffer = 0.0;
for (int n = 0; n < (Npoints - 1); n++)
{
buffer += 0.5 * (yptr[n+1] + yptr[n]) * (xptr[n+1] - xptr[n]);
trapzDiagFile << xptr[n] << "," << yptr[n] << std::endl;
}
trapzDiagFile.close();
return buffer;
}
I validated this function for the simple case where x contains 100 uniformly spaced points from 0 to 1, and y = x^2, and it returned 0.33334, as it should.
But when I use it for a different data set, it returns -3.431, which makes absolutely no sense. If you look in the attached image file, the integral I am referring to is the area under the curve between the dashed vertical lines.
It's definitely a positive number.
Moreover, I used the native trapz command in MATLAB on the same set of numbers and that returned 1.4376.
In addition, I translated the above C++ trapz function into MATLAB, line for line as closely as possible, and again got 1.4376.
I feel like there's something C++ related I'm not seeing here. If it is relevant, I am using minGW-w64.
Apologies for the vagueness of this post. If I knew more about what kind of issue I am seeing, it would be easier to be concise about it.
Plot of the dataset for which the trapz function (my homemade C++ version) returns -3.431:
Please check the value of xptr[Npoints - 1]. It may be less than xptr[Npoints - 2], and was not included in the values that you output.
I'm making a code that will calculate interest on a savings account. I listed all my variables as Double. I compiled it before writing the cout prompts at the bottom, and now that my code is finished, it won't compile. It gives me an error. I tried messing with the amount of parentheses, but nothing helped. Here is my code
FinalBalanceDaily = StartingPrinciple*(pow(1+((SimpInt/100)/365),(365*T)));
FinalBalanceMonthly = StartingPrinciple*(pow(1+((SimpInt/100)/12),(12*T)));
This is the error message.
:55: error: no matching function for call to âpow(double)â
and then it gives notes. The thing is, those two lines are on lines 53 and 54, 55 uses the exp function.
FinalBalanceCont = StartingPrinciple*(exp((SimpInt/100)*T));
EffectiveSimpInt1=(exp(SimpInt*T)-1)/T;
EffectiveSimpInt2=((pow(1+(SimpInt/365),(365*T)))-1)/T;
EffectiveSimpInt3=(pow(1+(SimpInt/12),(12*T))-1)/T;
These are the lines that use the pow() function
std::pow() need two parameters, but you just give one
I suggest that you can make your code more readable:
double x = 1 + (SimpInt / 100) / 12;
double y = 12 * T;
FinalBalanceMonthly = StartingPrinciple * pow(x, y);
By the way, I think that you put your "()" on the wrong place
based on this function. I'm trying to create two empty arrays (one for x and other for y), which later I will use to plot in python. But before anything this is what I have so far...
import math
x1=-2.0
x2=2.0
arr1 = []
arr2 = []
i=0
n=10
delta=(x2-x1)/n
for i in range (0,n+1):
x=x1+delta*i
arr1.append(x)
print arr1
# I have not called the w function yet
the code above creates a list of 10 numbers for now to keep it simple. Then it will send the elements of the array to the function below and compute the equation with certain numbers(infinite loop).
#This function will create the array list for y
import math
def w(x, limit):# the limit here to compare when the number is really small
suma = 0.0
sumb = 0.0
m=1
x=0
suma=suma+((1/(math.pow(2,m))*(math.sin(math.pow(2,m)*x)))
sumb=suma+((1/(math.pow(2,m+1))*(math.sin(math.pow(2,m+1)*x))) # I'm having a
#syntax error
#here
x+=0
if (abs (suma-sumb)<limit):
break:
else m+=1:
if (m<20):
break:
I will appreciate any help with my syntax errors or any suggestion. I just hope I was clear enough.
Thanks ahead of time
The syntax error is actually on the previous line, where the parenthesis are not balanced. You need an extra ) at the end of that line (and at the one you indicated as giving an error too btw).
There are also a few other issues
suma is set to zero, so suma = suma + ... is the same as suma = ..., but I'm guessing you still need to add while loop before this line.
On the line indicated, you have sumb = suma +, which is probably a copy/paste mistake.
The code block starting at x+=0 is indented by only 3 spaces instead of 4. This is probably not the case in your actual code, but if it is, Python will complain about that too.
else m+=1: should be else: m+=1 (colon directly after else, not at the end of the line.
break: should just be break (without to colon).