2

I'm translating some Fortran into Javascript and the order of operations for exponents is pretty opaque to me for a particular class of equations.

Here's an example of the Fortran equation:

x = 1+a*b**c*c**d

Exponents in Fortran are designated with the ** operator. This page gives some hints:

Arithmetic expressions are evaluated in accordance with the following priority rules:

  • All exponentiations are performed first; consecutive exponentiations are performed from right to left.
  • All multiplication and divisions are performed next, in the order in which they appear from left to right.

So it feels to me like to translate this into, say, Python, you'd end up with something like:

x = 1+a*pow(b,c)*pow(c,d)

But that isn't getting me the answers I'd expect it to, so I wanted to check if that seemed sane or not (because order of operations was never a strong suit of mine even in the best of circumstances, certainly not with languages I am not very familiar with).

Here's another puzzler:

x = a*(1-(1-a)**b)+(1-a)*(a)**(1/b)

Oy! This hurts my head. (Does putting that lone (a) in parens matter?) At least this one has parens, which suggests:

x = a*(1-pow(1-a,b))+(1-a)*pow(a,1/b)

But I'm still not sure I understand this.

nucleon
  • 861
  • 6
  • 22
  • It's part of a rather elaborate piece of code — in this example, a, b, and d are all constants (5.9, .09, and 3.8), whereas c is a ratio that can vary (in this particular constraint, it is at least greater than 1.0). As for what I expect it to evaluate to — I don't have any of that. All I have is whether the final output (which includes many equations like this) makes sense, and it doesn't at the moment; whether that is because of this or not, I don't know, but this seems like the most likely culprit at the moment. – nucleon Aug 16 '17 at 20:06
  • (And as I think is obvious — I didn't write the original FORTRAN. It is part of legacy code, so to speak, and the authors of it are not available. They did provide a "verbose" version of the equation in question, which _looks_ like it should evaluate the way I did it, but it was typed with a typewriter and is scanned from microfilm so I don't have a ton of confidence in the exponents being right.) – nucleon Aug 16 '17 at 20:07
  • As you are looking at expressions with single precision constants, they may be difficult to reproduce exactly in a language where pow() forces double. Since f90, in principle, Fortran has required options to avoid non-standard evaluation (but still with a fair amount of latitude for default). – tim18 Aug 17 '17 at 01:08
  • One can use powf in C. Not sure about javascript. – Vladimir F Героям слава Aug 17 '17 at 10:20

2 Answers2

5

You can look at this in terms of precedence of operators. ** is a higher precedence than *, higher than binary +. The expression 1+a*b**c*c**d is then like 1+a*(b**c)*(c**d).


More formally...

Expressions in Fortran are described by a grammar consisting of primaries and level-1 to level-5 expressions. Let's look at these using the example of the question

x = 1+a*b**c*c**d

the right-hand side of this is the expression of interest. As this is a so-called level-2 expression I'll explain only in terms up to that.

The primaries of this expression are the constant 1 and the variables a, b, c and d. We also have a number of operators +, ** and *.

The primaries are all level-1 expressions, and as there is no defined unary operator here we'll go straight to the level-2 expressions.

A level-2 expression is defined by the rules (quoting F2008 7.1.2.4):

  • mult-operand is level-1-expr [ power-op mult-operand ]
  • add-operand is [ add-operand mult-op ] mult-operand
  • level-2-expr is [ [ level-2-expr ] add-op ] add-operand

where power-op is **, mult-op * (or /) and add-op + (or -).

Putting the parsing together we have:

  • 1 + add-operand
  • 1 + ( add-operand * mult-operand )
  • 1 + ( ( a * mult-operand ) * ( mult-operand ) )
  • 1 + ( ( a * ( b ** c ) ) * ( c ** d ) )

As a final note, an expression enclosed in parentheses is a primary. This ensures that the expectation of precedence with parentheses is preserved.


This grammar also explains why a**b**c is evaluated as a**(b**c).

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • 1
    However, keep in mind that the compiler is free to reorder operations . The standard says, "Once the interpretation of a numeric intrinsic operation is established, the processor may evaluate any mathematically equivalent expression, provided that the integrity of parentheses is not violated. Two expressions of a numeric type are mathematically equivalent if, for all possible values of their primaries, their mathematical values are equal. **However, mathematically equivalent expressions of numeric type may produce different computational results.**" – Steve Lionel Aug 17 '17 at 14:18
  • @SteveLionel, is that comment about the potential numerical differences (which I didn't address in the answer, but is useful information relevant to the whole question), or do you think I can improve what I have included? – francescalus Aug 17 '17 at 14:29
  • @francescalus my comment was meant to add to your answer, since this is a common misunderstanding among Fortran users. The OP mentioned different answers, and it's important to recognize the difference between mathematical results and computational results. – Steve Lionel Aug 19 '17 at 00:10
1

For illustrate (no HTML in comments).

Fortran: 3**j**a**1 === Math: 3ja1 1+a*b**c*c**d === 1 + a×bc×cd

Serge3leo
  • 411
  • 2
  • 4