p-adic-numbers/modp.py

50 lines
1.6 KiB
Python
Raw Normal View History

2017-05-14 16:27:28 +02:00
class ModP(int):
2017-05-14 16:54:12 +02:00
'Integers mod p, p a prime power.'
2017-05-14 16:27:28 +02:00
def __new__(cls, p, num):
2017-05-14 19:22:39 +02:00
self = int.__new__(cls, int(num) % p)
2017-05-14 16:27:28 +02:00
self.p = p
2017-05-14 19:22:39 +02:00
return self
def __str__(self):
return "%d (mod %d)" % (self, self.p)
def __repr__(self):
return "%d %% %d" % (self, self.p)
2017-05-14 16:27:28 +02:00
# arithmetic
2017-05-16 00:38:57 +02:00
def __neg__(self):
return ModP(self.p, self.p - int(self))
2017-05-14 16:27:28 +02:00
def __add__(self, other):
return ModP(self.p, int(self) + int(other))
def __radd__(self, other):
return ModP(self.p, int(other) + int(self))
def __sub__(self, other):
return ModP(self.p, int(self) - int(other))
def __rsub__(self, other):
return ModP(self.p, int(other) - int(self))
def __mul__(self, other):
return ModP(self.p, int(self) * int(other))
def __rmul__(self, other):
return ModP(self.p, int(other) * int(self))
def __div__(self, other):
2017-05-14 19:22:39 +02:00
if not isinstance(other, ModP):
other = ModP(self.p, other)
2017-05-14 16:27:28 +02:00
return self * other._inv()
def __rdiv__(self, other):
return other * self._inv()
def _inv(self):
'Find multiplicative inverse of self in Z mod p.'
2017-05-14 18:55:09 +02:00
# extended Euclidean algorithm
rcurr = self.p
rnext = int(self)
tcurr = 0
tnext = 1
while rnext:
q = rcurr // rnext
rcurr, rnext = rnext, rcurr - q * rnext
tcurr, tnext = tnext, tcurr - q * tnext
if rcurr != 1:
raise ValueError("%d not a unit modulo %d" % (self, self.p))
return ModP(self.p, tcurr)