Task: Modular arithmetic







Python: import operator
import functools

@functools.total_ordering
class Mod:
    __slots__ = ['val','mod']

    def __init__(self, val, mod):
        if not isinstance(val, int):
            raise ValueError('Value must be integer')
        if not isinstance(mod, int) or mod<=0:
            raise ValueError('Modulo must be positive integer')
        self.val = val % mod
        self.mod = mod

    def __repr__(self):
        return 'Mod({}, {})'.format(self.val, self.mod)

    def __int__(self):
        return self.val

    def __eq__(self, other):
        if isinstance(other, Mod):
            if self.mod == other.mod:
                return self.val==other.val
            else:
                return NotImplemented
        elif isinstance(other, int):
            return self.val == other
        else:
            return NotImplemented

    def __lt__(self, other):
        if isinstance(other, Mod):
            if self.mod == other.mod:
                return self.val<other.val
            else:
                return NotImplemented
        elif isinstance(other, int):
            return self.val < other
        else:
            return NotImplemented

    def _check_operand(self, other):
        if not isinstance(other, (int, Mod)):
            raise TypeError('Only integer and Mod operands are supported')
        if isinstance(other, Mod) and self.mod != other.mod:
            raise ValueError('Inconsistent modulus: {} vs. {}'.format(self.mod, other.mod))

    def __pow__(self, other):
        self._check_operand(other)
        
        return Mod(pow(self.val, int(other), self.mod), self.mod)

    def __neg__(self):
        return Mod(self.mod - self.val, self.mod)

    def __pos__(self):
        return self 

    def __abs__(self):
        return self 



def _make_op(opname):
    op_fun = getattr(operator, opname)  
    def op(self, other):
        self._check_operand(other)
        return Mod(op_fun(self.val, int(other)) % self.mod, self.mod)
    return op

def _make_reflected_op(opname):
    op_fun = getattr(operator, opname)
    def op(self, other):
        self._check_operand(other)
        return Mod(op_fun(int(other), self.val) % self.mod, self.mod)
    return op


for opname, reflected_opname in [('__add__', '__radd__'), ('__sub__', '__rsub__'), ('__mul__', '__rmul__')]:
    setattr(Mod, opname, _make_op(opname))
    setattr(Mod, reflected_opname, _make_reflected_op(opname))

def f(x):
    return x**100+x+1

print(f(Mod(10,13)))





Fortran: module modular_arithmetic
  implicit none

  type :: modular
     integer :: val
     integer :: modulus
  end type modular

  interface operator(+)
     module procedure modular_modular_add
     module procedure modular_integer_add
  end interface operator(+)

  interface operator(**)
     module procedure modular_integer_pow
  end interface operator(**)

contains

  function modular_modular_add (a, b) result (c)
    type(modular), intent(in) :: a
    type(modular), intent(in) :: b
    type(modular) :: c

    if (a%modulus /= b%modulus) error stop
    c%val = modulo (a%val + b%val, a%modulus)
    c%modulus = a%modulus
  end function modular_modular_add

  function modular_integer_add (a, i) result (c)
    type(modular), intent(in) :: a
    integer, intent(in) :: i
    type(modular) :: c

    c%val = modulo (a%val + i, a%modulus)
    c%modulus = a%modulus
  end function modular_integer_add

  function modular_integer_pow (a, i) result (c)
    type(modular), intent(in) :: a
    integer, intent(in) :: i
    type(modular) :: c

    
    
    
    

    integer :: modulus
    integer :: base
    integer :: exponent

    modulus = a%modulus
    exponent = i

    if (modulus < 1) error stop
    if (exponent < 0) error stop

    c%modulus = modulus
    if (modulus == 1) then
       c%val = 0
    else
       c%val = 1
       base = modulo (a%val, modulus)
       do while (exponent > 0)
          if (modulo (exponent, 2) /= 0) then
             c%val = modulo (c%val * base, modulus)
          end if
          exponent = exponent / 2
          base = modulo (base * base, modulus)
       end do
    end if
  end function modular_integer_pow

end module modular_arithmetic




#define f(x) ((x)**100 + (x) + 1)

program modular_arithmetic_task
  use, intrinsic :: iso_fortran_env
  use, non_intrinsic :: modular_arithmetic
  implicit none

  type(modular) :: x, y

  x = modular(10, 13)
  y = f(x)

  write (*, '("    modulus 13:  ", I0)') y%val
  write (*, '("floating point:  ", E55.50)') f(10.0_real64)

end program modular_arithmetic_task