0
0

More than 1 year has passed since last update.

数値を範囲 "[0, 除数)" で保持する合同式向け数値クラス

Last updated at Posted at 2022-03-05

剰余数を保持する数値クラス

a, p を整数として

v = a % p

p と v の情報を保持し、各演算子を使うためのクラスです。例えば、次の計算は

7754077^{16307003-1} \equiv 1 \pmod{16307003}
>>> a = ModNumber(16307003, 7754077)
>>> a
(7754077 % 16307003)
>>> a ** (a.divisor - 1)
(1 % 16307003)

となります。保持される値 (a.value) は "[0, a.divisor)" です。

クラスが __repr__() 関数で返す文字列は
  "(value % divisor)"
形式です。

因みに「7754077 ** (16307003 - 1) % 16307003」の実行はやめましょう。

プログラム

modnum.py
from numbers import Integral


class ModNumber(Integral):
    def __init__(self, divisor, value=0):
        if divisor <= 0:
            raise ArithmeticError
        self.divisor = int(divisor)
        self.set_value(value)

    def get_divisor(self): return self.divisor
    def get_value(self): return self.value

    def set_value(self, value):
        divisor = self.divisor
        value = int(value) % divisor
        if value < 0:
            value += divisor
        self.value = value
        return self

    # override

    def __int__(self): return self.value
    def __repr__(self): return '(%d %% %d)' % (self.value, self.divisor)
    def __str__(self): return self.__repr__()

    def __eq__(self, other):
        if type(other) == ModNumber:
            if self.divisor != other.divisor:
                raise ArithmeticError
            value = other.value
        else:
            value = int(value)
        return (((self.value - value) % self.divisor) == 0)

    def __lt__(self, other): raise NotImplemented
    def __le__(self, other): raise NotImplemented

    def __neg__(self): return ModNumber(self.divisor, -self.value)
    def __pos__(self): return ModNumber(self.divisor, +self.value)
    def __invert__(self): raise NotImplemented

    def __add__(self, other): return ModNumber(self.divisor, self.value + other)
    def __sub__(self, other): return ModNumber(self.divisor, self.value - other)
    def __mul__(self, other): return ModNumber(self.divisor, self.value * other)
    def __pow__(self, other): return ModNumber(self.divisor, pow(self.value, other, self.divisor))

    def __divmod__(self, other):
        l, d = self.value, self.divisor
        return tuple(ModNumber(d, t) for t in (l / other, l % other))

    def __truediv__(self, other): return ModNumber(self.divisor, self.value / other)
    def __floordiv__(self, other): return ModNumber(self.divisor, self.value // other)
    def __mod__(self, other): return ModNumber(self.divisor, self.value % other)

    def __and__(self, other): return ModNumber(self.divisor, self.value & int(other))
    def __xor__(self, other): return ModNumber(self.divisor, self.value ^ int(other))
    def __or__(self, other): return ModNumber(self.divisor, self.value | int(other))

    def __lshift__(self, other): return self * ModNumber(self.divisor, 2)**other
    def __rshift__(self, other): return ModNumber(self.divisor, self.value >> int(other))

    def __radd__(self, other): return other + self.value
    def __rsub__(self, other): return other - self.value
    def __rmul__(self, other): return other * self.value
    def __rmod__(self, other): return other % self.value
    def __rtruediv__(self, other): return other % self.value
    def __rfloordiv__(self, other): return other // self.value
    def __rpow__(self, other): return other ** self.value

    def __rand__(self, other): return other & self.value
    def __rxor__(self, other): return other ^ self.value
    def __ror__(self, other): return other | self.value

    def __rlshift__(self, other): return other << self.value
    def __rrshift__(self, other): return other >> self.value

    def __iadd__(self, other): return self.set_value(self.value + int(other))
    def __isub__(self, other): return self.set_value(self.value - int(other))
    def __imul__(self, other): return self.set_value(self.value * other)
    def __itruediv__(self, other): return self.set_value(self.value // other)
    def __imod__(self, other): return self.set_value(self.value % other)

    def __abs__(self): return self
    def __ceil__(self): return self
    def __floor__(self): return self
    def __round__(self): return self
    def __trunc__(self): return self
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0