-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspeed_matters_calc.py
86 lines (67 loc) · 2.6 KB
/
speed_matters_calc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""Calculator script that cares about speed.
Does a binary search on possible floating point values, because a binary search is
much faster than for-looping over all floating point values; and speed matters."""
import sys
import actual_parser
class BinarySearchInterpreter(actual_parser.TreeInterpreter):
"""Interpret by getting continually closer to the result."""
def n_value(self, token):
# Nothing fancy here.
return float(token)
@staticmethod
def _binary_search(diff_evaluator):
def adjust_epsilon(initial_epsilon, value):
# we need to find the appropriate epsilon for this
# value size. For large numbers, a + epsilon == a,
# which means we need to adjust epsilon
epsilon = initial_epsilon
while value + epsilon == value:
epsilon *= 2
return epsilon
minv = -sys.float_info.max
maxv = sys.float_info.max
currv = minv
# We use sys.float_info.min because sys.float_info.epsilon is too big for
# small numbers, so it yields inexact results too often.
base_epsilon = sys.float_info.min
epsilon = adjust_epsilon(base_epsilon, currv)
while abs(diff_evaluator(currv)) > epsilon:
diff = diff_evaluator(currv)
if diff > 0:
maxv = currv
else:
minv = currv
currv = (minv + maxv) / 2
# adjust epsilon for the new value.
epsilon = adjust_epsilon(base_epsilon, currv)
return currv
def sum_value(self, lv, rv):
def sum_diff(possible_result):
return possible_result - lv - rv
return self._binary_search(sum_diff)
def sub_value(self, lv, rv):
def sub_diff(possible_result):
return possible_result - lv + rv
return self._binary_search(sub_diff)
def prod_value(self, lv, rv):
def prod_diff(possible_result):
return possible_result - (lv * rv)
return self._binary_search(prod_diff)
def div_value(self, lv, rv):
def div_diff(possible_result):
return possible_result - lv / rv
return self._binary_search(div_diff)
def _one_calc():
# Receive input from the user.
# Close the program when we get Ctrl+C or Ctrl+D.
try:
user_input = input()
except (KeyboardInterrupt, EOFError):
sys.exit(0)
parser = actual_parser.Parser(user_input)
ast = parser.parse()
interpreter = BinarySearchInterpreter(ast)
print(interpreter.eval())
if __name__ == "__main__":
while True:
_one_calc()