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)
|