-2

I was taught that in maths we evaluate things, with the acronym BODMAS Brackets, Orders(powers), Division, Multiplication, Addition, Subtraction.

I understand that in Javascript, * and / have equal precedence. + and - do too. And left associativity is used.

From the few examples I can think of, it seems to work just as well, producing the same results as BODMAs.

It looks like in the reality of the mathematical rules, it doesn't matter whether addition or subtraction is done first. It can matter whether additional or subtraction can done first 5-2+3. And for division and multiplication, it seems like it's only an issue when division is left of multiplication like 9/3*4 then division must be done first. And Javascript does / first in that instance.

But maybe there is an example where it breaks it! Where it gives a different result to standard maths.

Can Javascript break logical mathematical rules?

UPDATE-

To answer myself, when in Mathematics one says, PEDMAS where D and M are equal precedence and done left to right. And ditto A and S. You are saying they're left associative, i.e. where the implied brackets are. So programming languages that 'implement PEDMAS' the priority/precedence, and DM and AS being left associative, are totally following the PEDMAS rule. So, if there is any breaking of mathematical rules, it isn't from the associativity of M,D,A,S which is the same as in (conventional) mathematics. Also, in Mathematics, the unary minus is here- PEUDMAS so -5^2=-(5^2)=-25. exponent takes priority over unary minus. Though javascript probably gets that right. Apparently floating points in javascript break rules, as shown in some answers, though that wasn't what I had in mind as what I had in mind was purely re PEDMAS, but it seems parentheses make a difference with floating point numbers, where they shouldn't in normal mathematics, as shown in the answer I accepted.

barlop
  • 12,887
  • 8
  • 80
  • 109
  • 1
    well, division by zero is legal in javascript – doug Mar 29 '12 at 02:19
  • What would be the point of the math functions if they didn't return the correct results? – jahroy Mar 29 '12 at 02:19
  • inb4 floating point weirdness – david Mar 29 '12 at 02:19
  • 1
    So... where's the question? (Discuss x is not a question) – hkf Mar 29 '12 at 02:20
  • @hkf can you seriously not see what the question is? There's a question mark right at the end of the question/ "I am wondering, if javascript can produce a different result to what standard maths says. Any examples and descriptions?" Maybe doug has the closest answer i'll check it. Jarryd attempted an answer, he understood essentially what the question was asking – barlop Mar 29 '12 at 02:25
  • @jahroy apparently excel gets it wrong, but it's a bug and they leave it for backwards compatibility. -a^b. that is -(a^b) excel does it as (-a)^b. So -1^2 excel gets wrong. Excel says 1 and maths says -1. – barlop Mar 29 '12 at 08:42
  • 1
    BODMAS/PEDMAS is wrong. multiplication and division have equal priority and operators of that priority are done left to right. similarly with addition and subtraction. So 1-2+3 is (1-2)+3 subtraction before addition in that instance. – barlop Mar 29 '12 at 08:45
  • 1
    http://en.wikipedia.org/wiki/Order_of_operations#Mnemonics http://mathworld.wolfram.com/Precedence.html – JayC Mar 29 '12 at 14:57
  • @JayC ah ok, http://en.wikipedia.org/wiki/Order_of_operations#Mnemonics more correctly, only wrong when taught wrongly(I think they usually are taught wrongly).. "These mnemonics may be misleading when written this way, especially if the user is not aware that multiplication and division are of equal precedence, as are addition and subtraction" (but you still can't do them in any order. it has to be left to right) – barlop Mar 29 '12 at 23:35

4 Answers4

5

The only problem is with float numbers where the approximation of a division is extremely buggy. An actual example of this would be the fact that this will always alert false:

var a = 0.1;
var b = 0.2;
var c = 0.3;
if((a+b)+c == a+(b+c))
    alert("true");
else
    alert("false");

So basically the problem is with the Number object but not with the theoretical math implemented. As a programmer you probably understand the difference of the pre and post incrementation and the order of the operators so I do not really understand why did you gave as example 9/3*4 where the logic of the programmer applies and is verbose with the actual math.

Finally the answer you seek ( probably just out of curiosity ) is that the actual logic of the math you know it has not been changed in JavaScript, just some bugs from the roots of this language which still haunts us today.

helly0d
  • 828
  • 2
  • 10
  • 27
  • 1
    what has pre and post incrementation e.g. ++a and a++ got to do with it? – barlop Mar 29 '12 at 02:34
  • Through those i was referring to get different results in a portion of time. In some cases you can be fooled by the language you work in and it could have a bad effect like in this post: http://stackoverflow.com/q/7202157/1299642 – helly0d Mar 29 '12 at 02:39
  • corrected the code... [blush] – helly0d Mar 29 '12 at 02:43
  • I see the brackets right now ;-) impressively simple code. – barlop Mar 29 '12 at 02:43
  • a comment for anybody not that familiar with javascript. This one line(capital W, capital S for WScript) if ((0.1+0.2)+0.3==0.1+(0.2+0.3)) WScript.Echo("true"); else WScript.Echo("false"); in a file blah.js run with cscript blah.js demonstrates the above. – barlop Nov 07 '13 at 11:53
3

I am wondering, if javascript can produce a different result to what standard maths says.

Oh yes. Numbers in Javascript are represented by the IEEE double floating point. Because computers only have so much memory, mumbers in Javascript (or any programming language) do not have infinite precision.

Wikipedia provides a striking example of how two formulas that are exactly equivalent produces very different results on practical computers. For approximating pi, one may implement the two recurrence formulae shown on that page with the following Javascript:

function iteration_verA(t)
{
    return (Math.sqrt(t*t+1)-1)/t;
}

function iteration_verB(t)
{
    return t/(Math.sqrt(t*t+1)+1);
}

function calculate_pi()
{
    document.write("<table border=\"1\"><tr><td>Iteration Number</td>");
    document.write("<td>Using Version A</td><td>Using Version B</td></tr>");

    var tA = 1/Math.sqrt(3);
    var tB = 1/Math.sqrt(3);
    for(i = 0; i < 30; ++i)
    {
        tA = iteration_verA(tA);
        tB = iteration_verB(tB);
        var approxA = 12 * Math.pow(2, i) * tA;
        var approxB = 12 * Math.pow(2, i) * tB;
        document.write("<tr><td>" + i + "</td>");
        document.write("<td>" + approxA + "</td>");
        document.write("<td>" + approxB + "</td></tr>");
    }

    document.write("</table>");
}

calculate_pi();

iteration_verA() (Version A) and iteration_verB() (Version B) are mathematically equivalent. So their output should be the same, right?

#  Using Version A    Using Version B 
0  3.215390309173475  3.215390309173473 
1  3.1596599420975097 3.1596599420975013 
2  3.146086215131467  3.1460862151314357 
3  3.1427145996455734 3.1427145996453696 
4  3.141873049979866  3.141873049979825 
5  3.141662747055068  3.1416627470568503 
6  3.1416101765995217 3.1416101766046913 
7  3.141597034323337  3.1415970343215282 
8  3.141593748816856  3.1415937487713545 
9  3.141592927873633  3.1415929273850986 
10 3.1415927256225915 3.1415927220386157 
11 3.141592671741545  3.141592670702 
12 3.1415926189008862 3.141592657867846 
13 3.141592671741545  3.1415926546593082 
14 3.141591935881973  3.141592653857174 
15 3.141592671741545  3.14159265365664 
16 3.141581007579364  3.141592653606507 
17 3.141592671741545  3.1415926535939737 
18 3.1414061547376217 3.1415926535908403 
19 3.1405434924010995 3.141592653590057 
20 3.1400068646909682 3.1415926535898615 
21 3.1349453756588516 3.1415926535898126 
22 3.1400068646909682 3.1415926535898 
23 3.224515243534819  3.1415926535897975 
24 2.791117213058638  3.1415926535897966 
25 0                  3.1415926535897966 
26 NaN                3.1415926535897966 
27 NaN                3.1415926535897966 
28 NaN                3.1415926535897966 
29 NaN                3.1415926535897966

After 30 iterations using version B: 3.1415926535897966
Actual Value:                        3.1415926535897932384626433832795028841971...

Clearly, version B works and gives a very good approximation for pi (about 0.000000000000001% error), while version A doesn't even converge! This is due to the fact that version A is prone to numerical error which builds up on each iteration, while version B is much more robust in such scenarios.

This is of course, quite significant for any computer program that does any serious number crunching.

In silico
  • 51,091
  • 10
  • 150
  • 143
2

It looks like in the reality of the mathematical rules, it doesn't matter whether addition or subtraction is done first.

Not true: However you evaluate an expression of operators of equal precedence, the expression must be the same as if you evaluated them left to right. Subtraction is not associative.

Associativity means for things x,y,x and operator "$$" over such things , x $$ y $$ z = ( x $$ y) $$ z = x $$ (y $$ z)

Consider:

1 - 1 + 1

Normal evaluation:

(1 - 1) + 1 = 0 + 1 = 1

Right to left evaluation:

1 - (1 + 1) = 1 - 2 = -1

The reason you have flexibility with addition is that it is associative, which allows you to attack the evaluations in any which way (and of course if you take reflexivity commutativity into account you can order the numbers in the set of additions any which way as well). You're probably getting confused because mentally you're probably not really doing subtracting but (doing the equivalent of) adding inverses, in which case the only binary operator you're messing with is addition. The same thing happens with multiplication/division.

Now, here's an interesting fact. Addition of floating point numbers is not associative!

Try these both out:

Math.pow(10,100) + - Math.pow(10,100) + Math.pow(10,-100)

and

Math.pow(10,100) + (- Math.pow(10,100) + Math.pow(10,-100))

Both of these mathematically should evaluate to 1e-100 ( Math.pow(10,-100) or 1 x 10-100 ).... but they don't. In the second case, the gigantic floating point number approximating 1 x 10100 swallows up 1 x 10-100. The floating point would have to have 200 or so digits (base 10) of accuracy to account for both numbers. It's maybe a bit more tricky to come up with a similar example with the other operators, but certainly, through trial and error, you could probably come up with a few. What's important to remember is that the result of a floating point expression is an approximation, and hence, your results aren't strictly bound by mathematical rules.

JayC
  • 7,053
  • 2
  • 25
  • 41
  • thanks for correcting me.. i see though that another meaning of associativity, is like 'left to right associativity' e.g. while division is not associative, a compiler or interpreter it seems goes through an expression either left to right or right to left, for a group of operators at a set precedence level, and for division and muiltiplication, like addition and subtraction, it goes left to right. And this is how it's done in regular maths too, PEDMAS/PEMDAS/BODMAS is wrong.. 1-2+3 is done with left to right associativity. – barlop Mar 29 '12 at 08:34
  • so i suppose that's another meaning of associative besides saying an expression or sub expression of all + or all * is commutative and associative, and so can be grouped any way, and elemts can be swapped around and so it can be evaluated left to right or right to left. or perhaps it's the same meaning but when mixed symbols one says + is not associative and its associativity is left to right. whereas if it's not mixed symbols, = is associative meaning i suppose that its associativity can be left to right or right to left. – barlop Mar 29 '12 at 08:38
  • 1
    yeah, you're right, there's two concepts here: the associativity of the operators as defined in whatever programming language of as the normal order of evaluation for the operator (although, for most operators, I think they're left associative, the one operator I can think of that's generally right associative is the assignment operator), and there's the associative property http://en.wikipedia.org/wiki/Associative_property of the operators which allows us to pick and choose how we simplify an expression. – JayC Mar 29 '12 at 14:37
  • 1
    ... PEMDMAS isn't wrong, it's just a mnemonic. The last four letters form two groups of two. it could be PEDMSA, but that's just hard to say in English. I feel if I say anything more, I'm regurgitating http://en.wikipedia.org/wiki/Order_of_operations, so check that out. – JayC Mar 29 '12 at 14:55
-1

Times and divides have higher precedence in standard maths than plus and minus. If javascript has the same precedence for + - * and / then that will cause different results.

5 + 6 * 7

can be either

(5 + 6) * 7

or

5 + (6 * 7)

maths does the second, if the precedence is equal and it's left associative then you get the first.

Jarryd
  • 1,312
  • 11
  • 17
  • JavaScript does not give those four operators the same precedence, so I don't understand what your point is. – Chuck Mar 29 '12 at 02:25
  • I'm just answering how precedence can change. If the original poster got it wrong and javascript does have precedence, then that's not my problem. – Jarryd Mar 29 '12 at 05:28