We will take a look at a simple math problem that can be interpreted differently. This article is an attempt to unify Math and C++ parsing logic in the future.
Introduction
I recently saw a post about a simple math problem, to which I was sure there was a clear answer. I got impressed how many people get it wrong by so many different reasons, and even more impressed about how everybody was focusing at the "wrong part" of the equation.
C++ Sample - Doesn't Mean It Follows Math Rules
6/2(1+2) = 1 6/2*(1+2) = 9
Precedences by Layout
Before going to actual math rules, I want to let it clear that the way a formula looks indicates a lot to me.
I am tempted to say that, without any parenthesis, a formula like 10+20 / 1+2
seems to tell that we should calculate (10+20) / (1+2)
instead of 10 + (20/1) + 2
.
The math rules differ. Division comes before addition. Yet, why someone will add those extra spaces clearly visible in the formula if they expected 20/1
to be parsed before anything else?
I would agree to use just math rules if the formula was written like 10+20/1+2
. It would also make a lot of sense if it was written like 10 + 20/1 + 2
. But when it is written like 10+20 / 1+2
, I am at least curious (or maybe concerned) if this is a tricky question leading us to a mistake or if the person who wrote the formula really expected the division to take place last.
Maybe they wanted to express this:
And as that didn't have any parentheses, they kept the formula with no parentheses but with some extra spaces. Who knows?
The Initial Problem
Going back to the initial problem, it was presented with this equation:
If I translate this image to text, I am tempted to say it would look like this: 6 / 2(1+2)
.
I really see that there is extra space around the division symbol, and the entire 2(1+2)
seems to be packed together. That, alone, gives me the impression we should calculate 2(1+2)
before the division.
Again, I am talking about visual spaces and not math rules. So, to try to focus just on math rules, let me rewrite the expression:
6/2(1+2).
Now this problem only needs to follow math rules to be solved. I saw some people saying that multiplication happens before division, but those were largely outnumbered. Almost everybody agreed: First we need to resolve the parenthesis, then multiplication and division have the same priority, so we go left to right.
Then, they would do something like this:
6/2(1+2) -> We focus on (1+2), which becomes 3.
And then many people continued:
6/2*3 -> So we divide 6/2
3*3
9
Yet, my impression is that those people were just skipping one step here. When we calculate what's inside the parenthesis, we actually end-up with:
6/2(3)
We never said what happens to 2(3)
. And it seems that it is here where the real problem lies. Many people said that at that point, we already finished with the parentheses and that the expression should be rewritten as 6/2*3
. Yet, when I was in elementary school, we could never do that as that would be changing the priority of the things.
2(3)
should be seen as a packet that comes together, and we would not have solved the parentheses until the multiplication was finished. So, if we really wanted to rewrite the formula instead of doing the multiplication directly, we would rewrite the formula as 6/(2*3)
and we would still have parentheses to solve.
That, I remember, was a clear difference between something like:
6/2(1+2)
and consequently 6/2(3)
vs
6/2*(1+2)
and consequently 6/2*(3)
.
The 2(3)
was a group that needed to be solved together. Not because multiplication comes first, but because the 2 "owns" the 3 (or if you prefer, it is a kind of a function call like two(three)
). We might also say that to be able to get rid of the parentheses we needed to apply a special kind of multiplication. Something like 6/2*(3)
, on the other hand, had the (3)
clearly isolated and would become 6/2*3
to then follow the simple left to right rules.
This is so true that many calculators treat 6/2(3)
as a different expression than 6/2*3
or 6/2*(3)
. The interpretation that considers the expressions different is the strong grouping one (the one that I learned as a kid). The interpretation that considers the expressions as being equal is the weak grouping one.
I was actually surprised to know that it is considered "right by the new rules" to treat 2(3)
as a simple multiplication, like 2*3
, instead of a higher priority one, like (2*3)
and allowing the division of 6/2
happen before multiplying by 3
. Apparently, Google and Bing decided to use that rule.
Yet, I see that many people agree that 2(3)
seems to have an "implicit multiplication" and must be executed first. It might be just a difference on how schools teach these things and it doesn't seem to be a final answer or consensus here, to the point many just say the formula is "ambiguous" (or broken) and needs parentheses. Yet, why do we have "priority rules" if we need to use parentheses? I understand them when we want a different priority, not when we just have a plain expression.
More important, though, the entire issue is happening with a parentheses and how to resolve the implicit multiplication done with it.
Implicit Parentheses, "Packed Items" and Building Formulas
Although there are still differences in how that particular formula needs to be resolved, I think it is important to understand how formulas are created and combined together. For example, the diameter of a circle is two times its radius. For this formula, let's write:
d = 2r
Now, let's say I want to calculate how many circles can be aligned together in a particular length.
For example:
n = L/d
If I don't have d
, but have r
, I could replace d
by 2r
and end-up with this formula:
n = L / 2r
Notice that here I either:
- Did it wrong. Now people are going to do
L/2
and then multiply that by r
. The formula should use parentheses and be L/(2r)
. - Did it right. Not only the
/
has spaces around it visually indicating lower precedence, 2r
is a single "packet" that needs to be evaluated before the division.
Of course, if we were drawing it, it would look like:
And that would probably be clear enough without any need for parentheses. Needless to say, precedence rules or not, writing clean formulas is like writing clean code. It doesn't matter if a compiler can parse it and do the right thing. Are other people (or even us in the future) going to get it right?
Another Source
I personally loved this explanation from quora.
These are some examples found there:
Going Back to the Original Problem
Maybe it's because I am a programmer, but to me 2(3)
or similar really looks like a function call and I believe it should have higher priority. I know that was the rule when I was a kid, but nevermind that, I tried to replicate a multiplication behavior with just parenthesis. I was only able to do that in C++ (from the programming languages I normally use).
The C++ sample evaluates 6/2(1+2)
and 6/2*(1+2)
but I had to use named variables, like six/two(one+two)
for things to work. What I wanted was just to implement the operator ()
for int
s but, as I couldn't do that, I did the minimum implementation of an "int like" class with the operators for +
, *
, /
and the "implicit multiplication" operator ()
to make it work.
I did not alter in any way the order in which the C++ compiler evaluates the expression. I literally just added the () operator
to "integer like" objects. That lead to the results I was expecting.
You can execute the code at https://onlinegdb.com/Qul1J9eHe.
And, in case that's not working, this is a copy of the code:
#include <iostream>
class MyInt
{
public:
MyInt(int value):
_value(value)
{
}
MyInt operator ()(const MyInt &other)
{
return MyInt(_value * other._value);
}
int intValue() const
{
return _value;
}
MyInt operator + (const MyInt &other)
{
return MyInt(_value + other._value);
}
MyInt operator / (const MyInt &other)
{
return MyInt(_value / other._value);
}
MyInt operator * (const MyInt &other)
{
return MyInt(_value * other._value);
}
private:
int _value;
};
int main()
{
MyInt one(1);
MyInt two(2);
MyInt six(6);
auto equation1 = six/two(one+two);
std::cout << "6/2(1+2) = " << equation1.intValue() << std::endl;
auto equation2 = six/two*(one+two);
std::cout << "6/2*(1+2) = " << equation2.intValue() << std::endl;
return 0;
}
The output of this app is:
6/2(1+2) = 1
6/2*(1+2) = 9
Conclusion
Well... my only conclusion is that although sites like Google and Bing decided to use 2(3)
as a simple multiplication, that can get their parsing order scrambled if they follow a division, it is not really ambiguous by the formula what to do. The ambiguity seems to come from the (lack of) math rules around the issue. At least when programming in C++, we can actually find a non-ambiguous answer to how to interpret these odd expressions. I hope this helps to unify Math and C++ parsing logic in the future, but if that doesn't happen, it was just a funny exercise for me and I hope you have enjoyed.
History
- 4th December, 2021: Added the image about the different results from calculators
- 3rd December, 2021: Added some external Algebra examples and tried to clarify how the C++ sample works
- 2nd December, 2021: Moved the C++ Sample result to come after the Introduction
- 1st December, 2021: Initial version