I used fortran to write the following codes:
implicit none
real a,b
integer c
a=0.04
b=0.001
c=a/b
What i got is 39, which I can't figure out why. When I set real to a and b, they are single precision, which means it is accurate enough for this operation to get a right answer of 40.
Anyone can explain?
For c an integer (of default kind) the assignment c=a/b is equivalent to c=INT(a/b). INT is such that a real number ever so slightly smaller than 40 is mapped to 39.
What do you see with
print *, 0.04, 0.001, 0.04/0.001, INT(0.04/0.001)
? If you really want to see 40, then consider NINT, after reading the popular link.
Related
I have this line in fortran and I'm getting the compiler error in the title. dFeV is a 1d array of reals.
dFeV(x)=R1*5**(15) * (a**2) * EXP(-(VmigFe)/kbt)
for the record, the variable names are inherited and not my fault. I think this is an issue with not having the memory space to compute the value on the right before I store it on the left as a real (which would have enough room), but I don't know how to allocate more space for that computation.
The problem arises as one part of your computation is done using integer arithmetic of type integer(4).
That type has an upper limit of 2^31-1 = 2147483647 whereas your intermediate result 5^15 = 30517578125 is slightly larger (thanks to #evets comment).
As pointed out in your question: you save the result in a real variable.
Therefor, you could just compute that exponentiation using real data types: 5.0**15.
Your formula will end up like the following
dFeV(x)= R1 * (5.0**15) * (a**2) * exp(-(VmigFe)/kbt)
Note that integer(4) need not be the same implementation for every processor (thanks #IanBush).
Which just means that for some specific machines the upper limit might be different from 2^31-1 = 2147483647.
As indicated in the comment, the value of 5**15 exceeds the range of 4-byte signed integers, which are the typical default integer type. So you need to instruct the compiler to use a larger type for these constants. This program example shows one method. The ISO_FORTRAN_ENV module provides the int64 type. UPDATE: corrected to what I meant, as pointed out in comments.
program test_program
use ISO_FORTRAN_ENV
implicit none
integer (int64) :: i
i = 5_int64 **15_int64
write (*, *) i
end program
Although there does seem to be an additional point here that may be specific to gfortran:
integer(kind = 8) :: result
result = 5**15
print *, result
gives: Error: Result of exponentiation at (1) exceeds the range of INTEGER(4)
while
integer(kind = 8) :: result
result = 5**7 * 5**8
print *, result
gives: 30517578125
i.e. the exponentiation function seems to have an integer(4) limit even if the variable to which the answer is being assigned has a larger capacity.
I am new to Fortran and I was experimenting with int and double variables. I saw that
when you divide for example
integer:: a = 5
integer:: b = 2
the outcome is 2
However I was wondering when we use different types is there a difference of speed? Are they calculated the same way?
For example
double :: a = 2.0
integer :: b = 2
1) a**b
2) a**a
3) b**a
Of course the outcome for all these will be the same since they turn to double. However are they calculated the same way? Is there a difference in the speed they calculated?
EDIT : I must admit I did not know that the compiler plays a role. So far I know about 3 compilers : gfortran, nagfor and ifort. Personally I have experience in just gfortran and I tried and I got the same results in all the 3 calculations. However are they calculated the same way?
Normally, when optimizations are enabled, a**2 with a literal 2 will be changed to a*a. It is less likely, but not impossible, for the compiler to do such a thing for a variable integer exponent.
A completely generic exponentiation to a real exponent is implemented using logarithms. You just need the exp(x) function and then you can exponentiate any other number to the power of x if you know the logarithm of your number.
You can test the gfortran optimizations online https://godbolt.org/z/MvGEnn
You get a call to __powidf2() in the first case, and calls to pow() in the other cases.
Those are functions from the C runtime library.
double __powidf2 (double a, int b)
https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html
double pow(double x, double y);
https://linux.die.net/man/3/pow
The former one is a specialized function to exponentiate to an integer and is much faster, the other is for two doubles.
You can play with the optimization level and you can also make on of the numbers known.
Like this one, where the optimizer can treat it as a constant even when it is a variable:
https://godbolt.org/z/YT3KP8
However, the compiler will not do that, if the value is only known outside the subroutine.
But when you use -fwhole-program, the compiler is actually able the pre-compute the result from the subroutine https://godbolt.org/z/zs43jv
I hope it illustrates that the problem is actually quite complex and cannot be answered in all generality.
I am working on numerical analysis using a solver (the programming is based on object-oriented C++) compiled with double precision, and my unit is 64-bits. My problem is that when the solver computes a large number - say -1.45 to the power 21, to take an actual example - and stacks it in the allocated memory by passing this value to an existing variable, it is converted to 0. So of course, when I later use this variable in a division I get a segmentation fault. I do not understand how this process works, and because I use the DP, I do not see how to fix the issue. Could anyone give me a hand with this matter please ?
In case it helps: I just ran a test where I state a=-1.45e+21, and "print" the value which is returned correctly by the solver. But when I do not use the "e" exponent and enter the full value (with 19 zeros) I get 0 in return. So I guess the issue/limitation comes from the number of digits, any ideas ?? Thanks !
Edit: I post a summary of the steps I go through to compute one of the variables which poses an issue. The others being similarly defined.
First I initialise the field pointer lists:
PtrList<volScalarField> fInvFluids(fluidRegions.size());
Where the class of volScalarField is just an array of double. Then I populate the field pointer lists:
fInvFluids.set
(
i,
new volScalarField
(
IOobject
(
"fInv",
runTime.timeName(),
fluidRegions[i],
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
fluidRegions[i],
dimensionedScalar
(
"fInv",
dimensionSet(3,1,-9,-1,0,0,0),
scalar(0)
)
)
);
After this, I set the field regions:
volScalarField& fInv = fInvFluids[i];
And finally I compute the value:
// Info<< " ** Calculating fInv **\n";
fInv = gT*pow(pow(T/Tlambda, 5.7)*(1 - pow(T/Tlambda, 5.7)), 3);
Where T is field variable and Tlambda a scalar value defined at run time.
A double variable probably can't hold 19 zeroes either. A (decimal) digit takes more than 3 bits, so 19 zeroes will take at least 57 bits. A double typically has a mantissa which is only 53 bits.
However, that doesn't sound like the problem you have. In C++ code, expressions have a type as well. 1 is not the same as 1.0. The first is an int and the second a double. While you can convert an int to double, they're not the same. An int most likely can hold values up to 2 billion , but formally it may have a limit as low as 32767. The solution to your problem might be as simple as adding a twentieth zero : 100000000000000000000.0 making it a double.
Hi so the following are questions from my hw this week, I answered them in accordance with the material I found in my textbook but because we are graded extremely harsh in this class I thought I'd run them through a compiler to see if my answers were right. However when I run them in a c++ compiler I can't get the pow, ceil, or floor functions to return a floating point, they only return integers which disagrees with what my book says they should return??? I showed what my answers to the hw should be according to the book, and in parentheses what happens when i compile them.
question; what my book
says the
answer
should be; (what the compiler shows);
A) pow(2,3); 8.0; (my book says pow only returns a floating
point but this only returns an integer,
even when I change the function to be
pow(2.0,3.0) I only get 8);
B) fabs(-3.5); 3.5; (this one works, it returns 3.5);
C) sqrt(pow(3,2)); 2.8; (returns 2.82843, how am I supposed to
know how many decimals to put out?);
D) 7 / abs(-2); 3; (this one works);
E) ceil(5.8); 6.0; (only returns the integer 6);
F) floor(5.8); 5.0; (only returns the integer 5);
From what you have described, everything is working as expected. You haven't included the code you've written so this is somewhat of a guess - but you are asking the computer to print out the value of some numbers. You are getting 8 but you are expecting 8.0. Neither you nor the computer are wrong. You just need to ask the computer to print out decimal point values, even if the number you're asking to print is exactly an integer.
Question; what my book says the answer should be; (what the compiler shows);
The compiler doesn't show anything about types. (Well, it can, but you have to poke deep. For example, make it generate assembly, or use a trick that shows the type as a compiler error.)
Presumably you are basing your thoughts on what you see printed. For example, consider this C++11 program:
#include <cmath>
#include <iostream>
int main () {
auto pow_2_3 = std::pow(2,3);
// int eight {pow_2_3}; // Compilation error.
std::cout << pow_2_3 << '\n';
}
This prints "8" (not 8.0). Does that mean the type is an integer? Of course not. That "8" just means the default formatting is stripping the trailing zeros, and the decimal point as well.
You'll get a compilation error if you uncomment the commented-out line because a double cannot be narrowed to an integer. Not even if it's exact, and not even if it's known at compile time. The type of pow_2_3 is a double, just as the standard specifies. If std::pow(2,3) actually is an integer on your computer with your compiler, then you have a non-compliant compiler.
The same is true for std::ceil and std::floor. They return doubles, not integers.
As the title states I'm using FFTW (version 3.2.2) with Fortran 90/95 to perform a 2D FFT of real data (actually a field of random numbers). I think the forward step is working (at least I am getting some ouput). However I wanted to check everything by doing the IFFT to see if I can re-construct the original input. Unfortunately when I call the complex to real routine, nothing happens and I obtain no error output, so I'm a bit confused. Here are some code snippets:
implicit none
include "fftw3.f"
! - im=501, jm=401, and lm=60
real*8 :: u(im,jm,lm),recov(im,jm,lm)
complex*8 :: cu(1+im/2,jm)
integer*8 :: planf,planb
real*8 :: dv
! - Generate array of random numbers
dv=4.0
call random_number(u)
u=u*dv
recov=0.0
k=30
! - Forward step (FFT)
call dfftw_plan_dft_r2c_2d(planf,im,jm,u(:,:,k),cu,FFTW_ESTIMATE)
call dfftw_execute_dft_r2c(planf,u(:,:,k),cu)
call dfftw_destroy_plan(planf)
! - Backward step (IFFT)
call dfftw_plan_dft_c2r_2d(planb,im,jm,cu,recov(:,:,k),FFTW_ESTIMATE)
call dfftw_execute_dft_c2r(planb,cu,recov(:,:,k))
call dfftw_destroy_plan(planb)
The above forward step seems to work (r2c) but the backward step does not seem to work. I checked this by differencing the u and recov arrays - which ended up not being zero. Additionally the max and min values of the recov array were both zero, which seems to indicate that nothing was changed.
I've looked around the FFTW documentation and based my implementation on the following page http://www.fftw.org/fftw3_doc/Fortran-Examples.html#Fortran-Examples . I am wondering if the problem is related to indexing, at least that's the direction I am leaning. Anyway, if any one could offer some help, that would be wonderful!
Thanks!
Not sure if this is the root of all troubles here, but the way you declare variables may be the culprit.
For most compilers (this is apparently not even a standard), Complex*8 is an old syntax for single precision: the complex variable occupies a total of 8 bytes, shared between the real and the imaginary part (4+4 bytes).
[Edit 1 following Vladimir F comment to my answer, see his link for details:] In my experience (i.e. the systems/compiler I ever used), Complex(Kind=8) corresponds to the declaration of a double precision complex number (a real and an imaginary part, both of which occupy 8 bytes).
On any system/compiler, Complex(Kind=Kind(0.d0)) should declare a double precision complex.
In short, your complex array does not have the right size. Replace occurences of Real*8 and Complex*8 by Real(kind=8) and Complex(Kind=8) (or Complex(Kind=kind(0.d0)) for a better portability), respectively.