# Historical difference between / and ÷ in mathematical expressions

## Introduction:

Inspired by a discussion that is already going on for many years regarding the expression $$\6÷2(1+2)\$$.

With the expression $$\6÷2(1+2)\$$, mathematicians will quickly see that the correct answer is $$\1\$$, whereas people with a simple math background from school will quickly see that the correct answer is $$\9\$$. So where does this controversy and therefore different answers come from? There are two conflicting rules in how $$\6÷2(1+2)\$$ is written. One due to the part 2(, and one due to the division symbol ÷.

Although both mathematicians and 'ordinary people' will use PEMDAS (Parenthesis - Exponents - Division/Multiplication - Addition/Subtraction), for mathematicians the expression is evaluated like this below, because $$\2(3)\$$ is just like for example $$\2x^2\$$ a monomial a.k.a. "a single term due to implied multiplication by juxtaposition" (and therefore part of the P in PEMDAS), which will be evaluated differently than $$\2×(3)\$$ (a binomial a.k.a. two terms):

$$6÷2(1+2) → \frac{6}{2(3)} → \frac{6}{6} → 1$$

Whereas for 'ordinary people', $$\2(3)\$$ and $$\2×(3)\$$ will be the same (and therefore part of the MD in PEMDAS), so they'll use this instead:

$$6÷2(1+2) → 6/2×(1+2) → 6/2×3 → 3×3 → 9$$

Try it online!

## How?

### Processing leaf expressions

The helper function $$\h\$$ expects a leaf expression $$\e\$$ as input, processes all % symbols according to the rules of the year $$\y\$$ (defined in the parent scope) and evaluates the resulting string.

If $$\y<1918\$$, we transform X%Y into (X)/(Y), to enforce low precedence and repeat this process for the entire string from right to left to enforce right-to-left associativity.

Examples:

• 8%2 becomes (8)/(2), whose simplified form is 8/2
• 2+3%3+2 becomes (2+3)/(3+2)
• 8%2%2 becomes (8)/((2)/(2)), whose simplified form is 8/(2/2)

If $$\y\ge 1918\$$, each % is simply turned into a /.

h = e =>                    // e = input string
eval(                     // evaluate as JS code:
e.split%              //   split e on '%'
.reduceRight((a, c) =>  //   for each element 'c', starting from the right and
//   using 'a' as the accumulator:
y < 1918 ?            //     if y is less than 1918:
(${c})/(${a})     //       transform 'X%Y' into '(X)/(Y)'
:                     //     else:
c + '/' + a         //       just replace '%' with '/'
)                       //   end of reduceRight()
)                         // end of eval()

### Dealing with nested expressions

As mentioned above, the function $$\h\$$ is designed to operate on a leaf expression, i.e. an expression without any other sub-expression enclosed in parentheses.

That's why we use the helper function $$\g\$$ to recursively identify and process such leaf expressions.

g = e => (            // e = input
e !=                // compare the current expression with
( e = e.replace(  // the updated expression where:
/$$[^()]*$$/, //   each leaf expression '(A)'
h             //   is processed with h
)               // end of replace()
) ?               // if the new expression is different from the original one:
g               //   do a recursive call to g
:                 // else:
h               //   invoke h on the final string
)(e)                  // invoke either g(e) or h(e)
• Here's a version of h that's 9 bytes shorter: h=e=>eval(e.split%.reduceRight((a,c)=>y<1918?(${c})/(${a}):c+'/'+a)) Mar 1, 2019 at 4:07
• @ScottHamper Very nice. 'Right to left' should have ring a bell ... but it didn't. Mar 1, 2019 at 12:22

# Python 3.8 (pre-release), 324310 306 bytes

lambda s,y:eval((g(s*(y<1918))or s).replace('%','/'))
def g(s):
if'%'not in s:return s
l=r=j=J=i=s.find('%');x=y=0
while j>-1and(x:=x+~-')('.find(s[j])%3-1)>-1:l=[l,j][x<1];j-=1
while s[J:]and(y:=y+~-'()'.find(s[J])%3-1)>-1:r=[r,J+1][y<1];J+=1
return g(s[:l]+'('+g(s[l:i])+')/('+g(s[i+1:r])+')'+s[r:])

Try it online!

# Perl 5, 4797 95 bytes

/ /;$_="($`)";$'<1918?s-%-)/(-g:y-%-/-;$_=eval

$_="($F[0])";1while$F[1]<1918&&s-$$[^()]+$$-local$_=$&;s,%,)/((,rg.")"x y,%,,-ee;y-%-/-;$_=eval

TIO

• Very nice idea. However, you have an issue with 4%2%2 which returns 1 in both cases. (whereas it should return 4 pre-1918)
Feb 28, 2019 at 11:23
• it's true, i can't look anymore for the moment Feb 28, 2019 at 11:28
• @Dada, fixed (+50bytes) Feb 28, 2019 at 20:49

# Rust - 1066860783755 740 bytes

macro_rules! p{($x:expr)=>{$x.pop().unwrap()}}fn t(s:&str,n:i64)->f64{let (mut m,mut o)=(vec![],vec![]);let l=|v:&Vec<char>|*v.last().unwrap();let z=|s:&str|s.chars().nth(0).unwrap();let u=|c:char|->(i64,fn(f64,f64)->f64){match c{'÷'=>(if n<1918{-1}else{6},|x,y|y/x),'×'|'*'=>(4,|x,y|y*x),'-'=>(2,|x,y|y-x),'+'=>(2,|x,y|y+x),'/'=>(5,|x,y|y/x),_=>(0,|_,_|0.),}};macro_rules! c{($o:expr,$m:expr)=>{let x=(u(p!($o)).1)(p!($m),p!($m));$m.push(x);};};for k in s.split(" "){match z(k){'0'..='9'=>m.push(k.parse::<i64>().unwrap() as f64),'('=>o.push('('),')'=>{while l(&o)!='('{c!(o,m);}p!(o);}_=>{let j=u(z(k));while o.len()>0&&(u(l(&o)).0.abs()>=j.0.abs()){if j.0<0&&u(l(&o)).0<0{break;};c!(o,m);}o.push(z(k));}}}while o.len()>0{c!(o,m);}p!(m)}

Rust does not have anything like 'eval' so this is a bit tough. Basically, this is a bog-standard Djisktra shunting-yard infix evaluator with a minor modification. ÷ is an operator with a variable precedence: lower than everything else (but parenthesis) in <1918 mode, higher than everything else in >=1918 mode. It is also 'right associated' (or left?) for <1918 to meet the 4÷2÷2 specification, and association is 'faked' by making ÷ precedence negative, then during evaluation treating any precedence <0 as associated. There's more room for golfing but this is a good draft i think.

Ungolfed at play.rust-lang.org

• Do you really need that much whitespace? I think most of it could be removed. Mar 9, 2019 at 12:55
• @ivzem good point, but still its 3 times bigger than python Mar 9, 2019 at 19:04