How would this Fortran conditional expression evaluate? - if-statement

In the Fortran95 code below the variable NMOM is an integer and always equal to 3.
What would the value of P0 evaluate to, 1 or -1? The divide by 2 then multiply by 2 bit has me confused, I'm not sure why you would do this, but this was written by a non-programmer scientist back in the 90s who is no longer around to ask.
P0=1
IF(NMOM-NMOM/2*2.EQ.1)P0=-1
The code is compiled with lf95 on a Linux machine.

I don't know Fortran, but my guess is that it is testing if NMOM is odd or even. First, rewrite with parens to simulate operator precedence:
IF(NMOM-((NMOM/2)*2).EQ.1)P0=-1
And if we are using integer math then (NMOM/2)*2 == NMOM if it's even else it will equal NMOM-1 if it's odd.

Related

Floating point arithmetic in Fortran

I've inherited some Fortran code that I'm trying to make sense of. It uses REAL variables in many places that, I think, it shouldn't - but maybe I'm misunderstanding how this works in Fortran (as compared to C++ which I'm much more familiar with), hence this question.
So the variables in question are essentially 'categorical values', 'factors' or 'enums' depending on how you look at it/want to call it. They are of data type REAL and can only take on a finite number of pre-determined, integer values. So say variable a can only be of value 1, 2 or 3. These values are read in from external files; in these external files, they are represented as integers, so it's not a case of 'rounding issues in external data sources' or something.
However in the code, it never does a straight comparison, always a greater than/lower than check. So, instead of doing
if (a == 1) then
it does
if (a > 0.9 .and. a < 1.1) then
You can imagine that this gets very confusing/tiresome to read, especially when it needs to check if a value is one of multiple categories.
So I think this is a case where someone at some point heard 'never compare REAL values' (because of the nature of the finite precision of storing floating point values, this same problem exists in every programming language), but then didn't really understand when that applies (I guess the first error is that categorical values should have been represented as integer values but that situation is what it is for now).
OTOH maybe I'm just misunderstanding how REAL and INTEGER values are represented and work in Fortran? Could there ever be a case where
b = 1.5
a = REAL(INT(b))
if (a > 0.9 .and. a < 1.1) then
would make sense?
ONLY in the case you're not performing any operation with the real values (just assigning a value and comparing equality with the same literal you assigned, with same kind parameter), you won't need tolerance.
The thing is, for a real variable a such as:
Real a
a = 2
You can be sure that
a == 2
Will be always .true. . But e.g., for another real value represented by b:
a / b * b == 2
(Or any other operation) is not guaranteed to be .true.
If for some reason the variable has to stay REAL then you may use
the intrinsic Fortran function NINT (nearest integer) in the comparisons:
if( nint(a) == 1 ) then
....

Calculating pow with doubles gives wrong results

I'm programming a calculator on an Arduino and I'm trying to calculate pow and writing it to a string (result). This is my code:
dtostrf(exp(n*log(x)), 0, 5, result); // x ^ n
2 ^ 2 = 4.00000 // works fine
10 ^ 5 = 99999.9770 // should be 100000
What's wrong with my code and how can I always get the right result?
I mean how can I round it but still be able to use doubles ( e.g. 5.2 ^ 3.123 )
You're just hitting rounding errors. There's nothing you can do about this, except revert to an integer-based approach whenever the inputs are integers.
You could condition on whether the inputs are integers, and if so then use integer arithmetic; if not, then use doubles. But using exp and log will always introduce rounding errors, so you can't expect exact answers with that approach.
More precisely, to use integer arithmetic, you need the base to be an integer and the exponent to be a non-negative integer.
Since you are programming a calculator, speed is not your concern but the number of reliable digits is. So, you could try to use a double precision library. It uses 64-Bit-doubles but has only about 200 FLOPS at 16MHz CPU clock and much less at higher-order calculations like exp(), log(), or sin(). Thus, it will take a second after having typed in the digits and pressed the enter button but this was also the case with the old 8-Bit-based pocket caluclators.
See this Link (only in German)

Division by Multiplication and Shifiting

Why when you use the multiplication/shift method of division (for instance multiply by 2^32/10, then shift 32 to the right) with negative numbers you get the expected result minus one?
For instance, if you do 99/10 you get 9, as expected, but if you do -99 / 10 you get -10.
I verified that this is indeed the case (I did this manually with bits) but I can't understand the reason behind it.
If anyone can explain why this happens in simple terms I would be thankful.
Why when you use the multiplication/shift method of division (for instance multiply by 2^32/10, then shift 32 to the right) with negative numbers you get the expected result minus one?
You get the expected result, rounded down.
-99/10 is -9.9 which is -10 rounded down.
Edit: Googled a bit more, this article mentions that you're supposed to handle negatives as a special case:
Be aware that in the debug mode the optimized code can be slower, especially if you have both negative and positive numbers and you have to handle the sign yourself.

countdown from large number

I'm working on a solution to the third exercise of project Euler, and I need to loop over the odd numbers below sqrt(600851475143.0). But I can't subtract 2 from the number every time the loop iterates, it stays the same every time. According to this answer that is due to how numbers are stored and that everything just above and everything under the decimal point is lost. How do I solve this? I need decimal numbers, so I can't use an int (which would not have been big enough anyway).
Since you're looking for odd numbers, and odd numbers are by definition integer, just use an appropriate integer type instead of floating-point maths.

Need pow(-1,1.2) to be 1

I am using math.h with GCC and GSL. I was wondering how to get this to evaluate?
I was hoping that the pow function would recognize pow(-1,1.2) as ((-1)^6)^(1/5). But it doesn't.
Does anybody know of a c++ library that will recognize these? Perhaps somebody has a decomposition routine they could share.
Mathematically, pow(-1, 1.2) is simply not defined. There are no powers with fractional exponents of negative numbers, and I hope there is no library that will simply return some arbitray value for such an expression. Would you also expect things like
pow(-1, 0.5) = ((-1)^2)^(1/4) = 1
which obviously isn't desirable.
Moreover, the floating point number 1.2 isn't even exactly equal to 6/5. The closest double precision number to 1.2 is
1.1999999999999999555910790149937383830547332763671875
Given this, what result would you expect now for pow(-1, 1.2)?
If you want to raise negative numbers to powers -- especially fractional powers -- use the cpow() method. You'll need to include <complex> to use it.
It seems like you're looking for pow(abs(x), y).
Explanation: you seem to be thinking in terms of
xy = (xN)(y/N)
If we choose that N === 2, then you have
(x2)y/2 = ((x2)1/2)y
But
(x2)1/2 = |x|
Substituting gives
|x|y
This is a stretch, because the above manipulations only work for non-negative x, but you're the one who chose to use that assumption.
Sounds like you want to perform a complex power (cpow()) and then take the magnitude (abs()) of that after.
>>> abs(cmath.exp(1.2*cmath.log(-1)))
1.0
>>> abs(cmath.exp(1.2*cmath.log(-293.2834)))
913.57662451612202
pow(a,b) is often thought of, defined as, and implemented as exp(log(a)*b) where log(a) is natural logarithm of a. log(a) is not defined for a<=0 in real numbers. So you need to either write a function with special case for negative a and integer b and/or b=1/(some_integer). It's easy to special-case for integer b, but for b=1/(some_integer) it's prone to round-off problems, like Sven Marnach pointed out.
Maybe for your domain pow(-a,b) should always be -pow(a,b)? But then you'd just implement such function, so I assume the question warrants more explanation .
Like duskwuff suggested, a much more robust and "mathematical" solution is to use complex functions log and exp, but it's much more "complex" (excuse my pun) than it seems on the surface (even though there's cpow function). And it'll be much slower if you have to compute a lot of pow()s.
Now there's an important catch with complex numbers that may or may not be relevant to your problem domain: when done right, the result of pow(a,b) is not one, but often a few complex numbers, but in the cases you care about, one of them will be complex number with nearly-zero imaginary part (it'll be non-zero due to roundoff errors) which you can simply ignore and/or not compute in your code.
To demonstrate it, consider what pow(-1,.5) is. It's a number X such that X^2==-1. Guess what? There are 2 such numbers: i and -i. Generally, pow(-1, 1/N) has exactly N solutions, although you're interested in only one of them.
If the imaginary part of all results of pow(a,b) is significant, it means you are passing wrong values. For single-precision floating point values in the range you describe, 1e-6*max(abs(a),abs(b)) would be a good starting point for defining the "significant enough" threshold. The extreme "wrong values" would be pow(-1,0.5) which would return 0 + 1i (0 in real part, 1 in imaginary part). Here the imaginary part is huge relative to the input and real part, so you know you screwed up your input values.
In any reasonable single-return-result implementation of cpow() , cpow(-1,0.3333) will probably return something like -1+0.000001i and ignore two other values with significant imaginary parts. So you can just take that real value and that's your answer.
Use std::complex. Without that, the roots of unity don't make much sense. With it they make a whole lot of sense.