using System; namespace ModularArithmetic { interface IAddition { T Add(T rhs); } interface IMultiplication { T Multiply(T rhs); } interface IPower { T Power(int pow); } interface IOne { T One(); } class ModInt : IAddition, IMultiplication, IPower, IOne { private int modulo; public ModInt(int value, int modulo) { Value = value; this.modulo = modulo; } public int Value { get; } public ModInt One() { return new ModInt(1, modulo); } public ModInt Add(ModInt rhs) { return this + rhs; } public ModInt Multiply(ModInt rhs) { return this * rhs; } public ModInt Power(int pow) { return Pow(this, pow); } public override string ToString() { return string.Format("ModInt({0}, {1})", Value, modulo); } public static ModInt operator +(ModInt lhs, ModInt rhs) { if (lhs.modulo != rhs.modulo) { throw new ArgumentException("Cannot add rings with different modulus"); } return new ModInt((lhs.Value + rhs.Value) % lhs.modulo, lhs.modulo); } public static ModInt operator *(ModInt lhs, ModInt rhs) { if (lhs.modulo != rhs.modulo) { throw new ArgumentException("Cannot add rings with different modulus"); } return new ModInt((lhs.Value * rhs.Value) % lhs.modulo, lhs.modulo); } public static ModInt Pow(ModInt self, int p) { if (p < 0) { throw new ArgumentException("p must be zero or greater"); } int pp = p; ModInt pwr = self.One(); while (pp-- > 0) { pwr *= self; } return pwr; } } class Program { static T F(T x) where T : IAddition, IMultiplication, IPower, IOne { return x.Power(100).Add(x).Add(x.One()); } static void Main(string[] args) { ModInt x = new ModInt(10, 13); ModInt y = F(x); Console.WriteLine("x ^ 100 + x + 1 for x = {0} is {1}", x, y); } } }