-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcalculator.py
More file actions
177 lines (134 loc) · 5.66 KB
/
calculator.py
File metadata and controls
177 lines (134 loc) · 5.66 KB
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
"""
Branchless Calculator — Operation selection without if/else chains.
PATTERN: Function Table Lookup
Instead of a chain of if/elif checks to pick an operation, we store all
operations in a list (a "table") and use the index to grab the right one.
Traditional (branching):
if op == 0: return a + b
elif op == 1: return a - b
elif op == 2: return a * b
...
Branchless (table lookup):
OPERATIONS = [add, subtract, multiply, divide, modulo]
return OPERATIONS[op_index](a, b) # One lookup, no branches!
WHY THIS IS BRANCHLESS:
Array indexing is just pointer arithmetic: base_address + index * element_size.
The CPU doesn't need to "choose" — it computes the address and jumps there.
"""
# ──────────────────────────────────────────────
# Operation functions
# ──────────────────────────────────────────────
def add(a, b):
"""Addition — trivially branchless."""
return a + b
def subtract(a, b):
"""Subtraction — trivially branchless."""
return a - b
def multiply(a, b):
"""Multiplication — trivially branchless."""
return a * b
def divide(a, b):
"""
Division with branchless zero-safety.
PROBLEM: We can't divide by zero, but we also can't use `if b == 0`.
TRICK: Convert the boolean (b == 0) to 0 or 1, then use arithmetic.
Step 1: is_zero = int(b == 0) → 1 if b is zero, 0 otherwise
Step 2: safe_b = b + is_zero → if b=0, becomes 1; if b≠0, unchanged
Step 3: result = a / safe_b → safe to divide (never divides by 0)
Step 4: result * (1 - is_zero) → zeroes out the result if b was 0
WORKED EXAMPLE (a=10, b=0):
is_zero = int(0 == 0) = 1
safe_b = 0 + 1 = 1
result = 10 / 1 = 10.0
final = 10.0 * (1 - 1) = 10.0 * 0 = 0.0 ✓ (safe, no crash)
WORKED EXAMPLE (a=10, b=5):
is_zero = int(5 == 0) = 0
safe_b = 5 + 0 = 5
result = 10 / 5 = 2.0
final = 2.0 * (1 - 0) = 2.0 * 1 = 2.0 ✓
"""
is_zero = int(b == 0)
safe_b = b + is_zero # Avoid division by zero
result = a / safe_b
return result * (1 - is_zero) # Return 0 if b was originally zero
def modulo(a, b):
"""
Modulo with branchless zero-safety.
Same trick as divide() — see that function's docstring for explanation.
"""
is_zero = int(b == 0)
safe_b = b + is_zero
result = a % safe_b
return result * (1 - is_zero)
# ──────────────────────────────────────────────
# Lookup tables
# ──────────────────────────────────────────────
# This IS the branchless magic: a list of functions indexed by operation number.
# Index 0 → add
# Index 1 → subtract
# Index 2 → multiply
# Index 3 → divide
# Index 4 → modulo
OPERATIONS = [add, subtract, multiply, divide, modulo]
OP_NAMES = ["+", "-", "*", "/", "%"]
# Number of supported operations (used for clamping)
NUM_OPS = len(OPERATIONS) # 5
def branchless_clamp(value, lo, hi):
"""
Clamp `value` to [lo, hi] without using if/else.
TRICK: Use int(condition) to create a 0/1 flag, then multiply.
Step 1: Check if below minimum
below = int(value < lo) → 1 if too low, 0 otherwise
value = value + (lo - value) * below
When below=1: value + (lo - value) = lo (snapped to minimum)
When below=0: value + 0 = value (unchanged)
Step 2: Check if above maximum (same idea)
above = int(value > hi)
value = value + (hi - value) * above
"""
below = int(value < lo)
value = value + (lo - value) * below
above = int(value > hi)
value = value + (hi - value) * above
return value
def calculate(a, b, op_index):
"""
Perform a calculation using branchless table lookup.
Args:
a: First operand
b: Second operand
op_index: Which operation (0=add, 1=sub, 2=mul, 3=div, 4=mod)
Returns:
The result of the chosen operation.
"""
# Clamp index to valid range [0, NUM_OPS-1] — branchlessly
safe_index = branchless_clamp(op_index, 0, NUM_OPS - 1)
# Direct table lookup — no if/elif chain!
return OPERATIONS[safe_index](a, b)
def get_op_symbol(op_index):
"""Get operation symbol using table lookup (branchless)."""
safe_index = branchless_clamp(op_index, 0, NUM_OPS - 1)
return OP_NAMES[safe_index]
# ──────────────────────────────────────────────
# Demo
# ──────────────────────────────────────────────
if __name__ == "__main__":
test_cases = [
(10, 5, 0), # 10 + 5
(10, 5, 1), # 10 - 5
(10, 5, 2), # 10 * 5
(10, 5, 3), # 10 / 5
(10, 3, 4), # 10 % 3
(10, 0, 3), # 10 / 0 (safe division → returns 0)
]
print("Branchless Calculator Demo")
print("=" * 40)
for a, b, op in test_cases:
result = calculate(a, b, op)
symbol = get_op_symbol(op)
print(f" {a} {symbol} {b} = {result}")
print()
print("KEY TECHNIQUE: Function table lookup")
print(" OPERATIONS[index](a, b)")
print(" → replaces if/elif/switch chains")
print(" → one array access, zero branches")