Thun/bigjoyints/big.py

91 lines
1.9 KiB
Python

import ctypes
def is_i32(n):
return -2**31 <= n < 2**31
class OberonInt:
'''
Let's model the Oberon RISC integers,
32-bit, two's complement.
'''
def __init__(self, initial=0):
assert is_i32(initial)
self.value = ctypes.c_int32(initial)
assert self.value.value == initial
def __add__(self, other):
'''
Return carry bit and new value.
'''
if not isinstance(other, OberonInt):
other = OberonInt(other)
n = self.value.value + other.value.value
carry = not is_i32(n)
if carry:
n &= (2**31-1)
return int(carry), OberonInt(n)
__radd__ = __add__
def negate(self):
# Instead of binary ops, just cheat:
return OberonInt(-self.value.value)
def __sub__(self, other):
if not isinstance(other, OberonInt):
other = OberonInt(other)
return self + other.negate()
__rsub__ = __sub__
def __repr__(self):
#b = bin(self.value.value & (2**32-1))
return f'OberonInt({self.value.value})'
def __eq__(self, other):
assert isinstance(other, OberonInt)
return self.value.value == other.value.value
obmin, zero, one, obmax = map(OberonInt, (
-(2**31),
0,
1,
2**31-1,
))
# Addition
carry, z = obmax + one
assert carry
assert z == zero
# Negation
negative_one = one.negate()
carry, m = obmin + negative_one
assert carry
assert m == obmax
# Ergo, subtraction.
carry, m = obmin - one
assert carry
assert m == obmax
carry, hmm = obmax + obmax
assert carry
assert hmm.value.value == 2**31 - 2
carry, eh = obmax - hmm
assert not carry
assert eh == one
assert (hmm + one)[1] == obmax
## if initial >= 2**31:
## raise ValueError(f'too big: {initial!r}')
## if initial < -2**31:
## raise ValueError(f'too small: {initial!r}')