diff --git a/Maths/ModularArithmetic.js b/Maths/ModularArithmetic.js new file mode 100644 index 0000000000..26c54ebbb4 --- /dev/null +++ b/Maths/ModularArithmetic.js @@ -0,0 +1,56 @@ +import { extendedEuclideanGCD } from './ExtendedEuclideanGCD' + +/** + * https://brilliant.org/wiki/modular-arithmetic/ + * @param {Number} arg1 first argument + * @param {Number} arg2 second argument + * @returns {Number} + */ + +export class ModRing { + constructor (MOD) { + this.MOD = MOD + } + + isInputValid = (arg1, arg2) => { + if (!this.MOD) { + throw new Error('Modulus must be initialized in the object constructor') + } + if (typeof arg1 !== 'number' || typeof arg2 !== 'number') { + throw new TypeError('Input must be Numbers') + } + } + /** + * Modulus is Distributive property, + * As a result, we separate it into numbers in order to keep it within MOD's range + */ + + add = (arg1, arg2) => { + this.isInputValid(arg1, arg2) + return ((arg1 % this.MOD) + (arg2 % this.MOD)) % this.MOD + } + + subtract = (arg1, arg2) => { + this.isInputValid(arg1, arg2) + // An extra MOD is added to check negative results + return ((arg1 % this.MOD) - (arg2 % this.MOD) + this.MOD) % this.MOD + } + + multiply = (arg1, arg2) => { + this.isInputValid(arg1, arg2) + return ((arg1 % this.MOD) * (arg2 % this.MOD)) % this.MOD + } + + /** + * + * It is not Possible to find Division directly like the above methods, + * So we have to use the Extended Euclidean Theorem for finding Multiplicative Inverse + * https://github.com/TheAlgorithms/JavaScript/blob/master/Maths/ExtendedEuclideanGCD.js + */ + + divide = (arg1, arg2) => { + // 1st Index contains the required result + // The theorem may have return Negative value, we need to add MOD to make it Positive + return (extendedEuclideanGCD(arg1, arg2)[1] + this.MOD) % this.MOD + } +} diff --git a/Maths/test/ModularArithmetic.test.js b/Maths/test/ModularArithmetic.test.js new file mode 100644 index 0000000000..af42e243de --- /dev/null +++ b/Maths/test/ModularArithmetic.test.js @@ -0,0 +1,45 @@ +import { ModRing } from '../ModularArithmetic' + +describe('Modular Arithmetic', () => { + const MOD = 10000007 + let ring + beforeEach(() => { + ring = new ModRing(MOD) + }) + + describe('add', () => { + it('Should return 9999993 for 10000000 and 10000000', () => { + expect(ring.add(10000000, 10000000)).toBe(9999993) + }) + it('Should return 9999986 for 10000000 and 20000000', () => { + expect(ring.add(10000000, 20000000)).toBe(9999986) + }) + }) + + describe('subtract', () => { + it('Should return 1000000 for 10000000 and 9000000', () => { + expect(ring.subtract(10000000, 9000000)).toBe(1000000) + }) + it('Should return 7 for 10000000 and 20000000', () => { + expect(ring.subtract(10000000, 20000000)).toBe(7) + }) + }) + + describe('multiply', () => { + it('Should return 1000000 for 100000 and 10000', () => { + expect(ring.multiply(100000, 10000)).toBe(9999307) + }) + it('Should return 7 for 100000 and 10000100', () => { + expect(ring.multiply(10000000, 20000000)).toBe(98) + }) + }) + + describe('divide', () => { + it('Should return 4 for 3 and 11', () => { + expect(ring.divide(3, 11)).toBe(4) + }) + it('Should return 2 for 18 and 7', () => { + expect(ring.divide(18, 7)).toBe(2) + }) + }) +})