Solving linear equations
in "Pure c"
github @observerss
jingchaohu AT gmail DOT com
2014. Caigin100 Inc.
Problem
Logan's middle school computer contest problem:
how to solve these linear equations?
3*x + 4 = 6
(4+x*2)*5+3*2+5*x=1
(4-3)*(2+7)/2 = x - 5*4+3*x
x = ?
During 5.1 festival, I was thinking ...
I am now a more capable programmer than he was,
can I solve this problem?
EASY!
matlab, yacas,
or sympy
>>> import sympy
>>> sympy.solve('2*x + 5 - (3*x-2) - x - 5', 'x')
[1]
NO, that's cheating
RULES
-
no third party library
-
no fancy eval-like operation
- no regular expressions
-
let's do it in pure c
- except using python for better illustration
How humans do it?
2*(x + 5) - (3*x-2)=x + 5
rule1: a = b => a - b = 0
2*(x +5)-(3*x-2)-(x+5) = 0
rule2: a*(b+c) = a*b+a*c
2*x+2*5-(3*x-2)-(x+5) = 0
rule3: a-(b+c) = a-b-c; a-(b-c) = a-b+c
2*x+10-3*x+2-x-5 = 0
rule4: a + b + c = a + c + b; a + b - c = a + b + (-c) = a + (-c) + b = a - c +b
2*x-3*x-x+10+2-5 = 0
then we apply rule2 again (reversed)
-2*x+7=0
IT's ok, but...
-
a lot of rules
-
a lot of parsers
-
a lot of code
-
seems too complicated to me
Another APProach
for f(x) = (any very complex linear expression)
there is a simplified version, that is,
f(x)=ax + b
then:
f(1) = a + b
f(0) = b
Our Situation
f(x) = 2*(x+5) - (3*x-2) - x - 5
f(1) = 2*(1+5)-(3*1-2)-1-5 = 5
f(0) = 2*(0+5)-(3*0-2)-0-5= 7
so:
a+b = 5 = f(1)
b = 7 = f(0)
ax+b=0
=>
x = -b/a = -f(0)/(f(1)-f(0))
Full Algorithm
- move the right of equation to left
- replace x with 1 and 0 respectively and evaluate them
-
calculate the x according to step2's result
FULL ALGORITHM
- move the right of equation to left
- equation.replace('=', '-(') + ')'
- replace x with 1 and 0 respectively and evaluate them
- equation.replace('x', 1)
- how to evaluate a mathematic expression?
- calculate the x according to step2's results
IMPLEmentation
def solve(equation, sym='x'):
expr = equation.replace('=', '-(') + ')'
expr = expr.replace(' ', '')
v1 = calc(expr.replace(sym, '1'))
v2 = calc(expr.replace(sym, '2'))
return 1.*(-v2)/(v1-v2)
How to implement "calc"?
def calc(expression):
""" calculate the result of a numeral algebra expression """
return eval(expression)
No, there's no "eval" in C
How?
DATA structure Textbook
-
infix expression -> postfix expression
- shutting-yard algorithm
-
evaluate postfix expression
- or simply combine the above steps
Implementing calc
def calc(expr):
""" calculate numeral expression """
op_stack = []
num_stack = []
i = 0
while i < len(expr):
tok, i = next_token(expr, i)
if tok in ops: # + - * / ( )
if len(op_stack) == 0:
op_stack.append(tok)
elif tok == '(':
op_stack.append(tok)
elif tok == ')': # evaluate to last paired '('
while op_stack[-1] != '(':
evaluate_last()
op_stack.pop()
else:
while should_evaluate_last(tok):
evaluate_last()
op_stack.append(tok)
else:
num_stack.append(tok)
while len(num_stack) > 1:
evaluate_last()
return num_stack[0]
3+5*6
-
num: 3; op: []
- num: 3; op +
- num: 3 5; op +
- num: 3 5; op + *, * has higher priority than +, do nothing
- num: 3 5 6; op + *
- num: 3 30; op +
- num: 33; op []
7*(5+3)+2
-
num: 7; op []
- num: 7; op *
- num: 7; op * (; do nothing
- num: 7 5; op * (
- num: 7 5; op * ( +; + has higher priority than (, do nothing
- num: 7 5 3; op * ( +
- num: 7 5 3; op * ( + ); should evaluate all between ()
- num: 7 15; op *
- num: 7 15; op * +, + has lower priority than *, should * first
- num: 105; op +
- num: 105 2; op +
- num: 107; op []
Wrap up
-
convert the original problem to an evaluation problem
-
use textbook data structures to implement a calculator
-
We beat Logan(at his 15s), Yay!
- https://github.com/observerss/linearequation
THANK you!
Solving linear equations
By jingchaohu
Solving linear equations
- 1,676