Repository: pbiswas101/Mathball (js)

Issue:
Kaprekar Number
### Do the checklist before filing the issue:

- [ ] Is this something you can **debug and fix**?
- [x] Do you have Node.js and all the relevant dev-dependencies installed?
- [ ] Is this a **feature request** that you can add?

###### NOTE: Provide a clear and concise description of the feature that needs to be added! Or if its a bug, then provide the necessary steps to reproduce it.

- *Give your answer below:*

------------

[Function: **M.isKaprekar()**] needs to be added!
For more info:

https://www.geeksforgeeks.org/kaprekar-number/

*M.isKaprekar()* needs to accept a positive integer and all other arguments passed should throw a type error which needs to be handled gracefully! For error handling, you should refer to how other features like M.isArmstrong() is implemented.

Pull request:
Arithmetic Modules(#112)
*Added Arithmetic Modules' functions

*Added Arithmetic modules in index and readme

*Added Unit Tests of Arithmetic Modules

### Do the checklist before submitting the PR:

- [:heavy_check_mark:] Have you read the guidelines mentioned in **CONTRIBUTING.md**?
- [:heavy_check_mark:] Have you squashed your commits?

**Q**: What version of *Node.js* you've used in the project? (`e.g. Node v10.11.0`)
**A**:v11.10.1

**Q**: Mention the *Issue Number*! (`e.g. Fixed #8`)
**A**:#112

- *Give additional information regarding the PR below:*

------------


Patch:
diff --git a/README.md b/README.md
index 7ee5809..9a8047e 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ $ npm install mathball --save
 
 - **Range of Numbers** - [rangePrime][7] - [range][66] - [rangePalindrome][6]
 
-- **Mathematical Utilities** - [Complex][49] - [frequency][40] - [gcd][10] - [getAllPerm][55] - [isEven][11] - [isOdd][12] - [lcm][13] - [length][14] - [max][15] - [median][64] - [min][16] - [modInv][39] - [nCr][48] - [pow][46] - [sort][17] - [sum][18] - [toDegrees][50] - [toRadians][51] - [matrixMultiply][58] - [matrixExpo][59] - [matrixChain][60] - [count][61] - [avg][62] - [findPrimeFactors][63] - [phi][67]
+- **Mathematical Utilities** - [Complex][49] - [frequency][40] - [gcd][10] - [getAllPerm][55] - [isEven][11] - [isOdd][12] - [lcm][13] - [length][14] - [max][15] - [median][64] - [min][16] - [modInv][39] - [nCr][48] - [pow][46] - [sort][17] - [sum][18] - [toDegrees][50] - [toRadians][51] - [matrixMultiply][58] - [matrixExpo][59] - [matrixChain][60] - [count][61] - [avg][62] - [findPrimeFactors][63] - [phi][67] - [addition][112] - [subtraction][113] - [multiplication][114] - [division][115] - [absolute][116]
 
 - **Data Structures** - [priorityQueue][44] - [stack][53] - [graph][57]
 
@@ -133,3 +133,8 @@ The MIT License 2019 - [Priyabrata Biswas][20].
 [64]: https://github.com/pbiswas101/Mathball/blob/master/src/median/index.js
 [66]: https://github.com/pbiswas101/Mathball/blob/master/src/range/index.js
 [67]: https://github.com/pbiswas101/Mathball/blob/master/src/totient/index.js
+[112]: https://github.com/pbiswas101/Mathball/blob/master/src/addition/index.js
+[113]: https://github.com/pbiswas101/Mathball/blob/master/src/subtraction/index.js
+[114]: https://github.com/pbiswas101/Mathball/blob/master/src/multiplication/index.js
+[115]: https://github.com/pbiswas101/Mathball/blob/master/src/division/index.js
+[116]: https://github.com/pbiswas101/Mathball/blob/master/src/absolute/index.js
diff --git a/src/absolute/index.js b/src/absolute/index.js
new file mode 100644
index 0000000..c5a7a54
--- /dev/null
+++ b/src/absolute/index.js
@@ -0,0 +1,86 @@
+/*Absolute value across all data-types and data-structures
+*Function: M.abs(m,n)
+*/
+const Complex = require('../complex');
+const validate = require('../validation/argument-length');
+
+const abs = (a) => {
+	switch(a.constructor){
+	case Number:
+		return absNum(a);
+	case String:
+		return absString(a);
+	case Array:
+		return absArray(a);
+	case Complex:
+		return absComplex(a);
+	}
+};
+
+const absNum = (a) => {
+	return Math.abs(a);
+};
+
+const absString = (a) => {
+	let absolute = Math.abs(Number(a));
+	return absolute.toString(10);
+};
+
+//Determinant of a matrix
+
+function det(a,n){
+        let determinant = 0, c1, c2, sign =  1;
+        let detArr = [...Array(n)].map(x => Array(n).fill(0));
+        if(n === 1){
+                return a[0][0];
+        }
+        else if(n === 2){
+                determinant = a[0][0]*a[1][1]- a[0][1]*a[1][0];
+        return determinant;
+        }
+        else{
+                for(let i = 0; i < n; i++){
+                        c1 = 0, c2 = 0;
+                        for(let j = 0; j < n; j++){
+
+                        for(let k = 0; k < n; k++){
+                                if(j != 0 && k != i){
+                                        detArr[c1][c2] = a[j][k];
+                                        c2++;
+                                        if(c2 > n - 2){
+                                        c1++;
+                                        c2 = 0;
+                                        }
+                                }
+                        }
+                }
+		determinant = determinant + sign*a[0][i]* det(detArr, n - 1);
+		sign = -1*sign;
+		}
+		return determinant;
+	}
+}
+
+
+const absArray = (a) => {
+	if(a[0].length === undefined){
+		return 0;
+	}
+
+	if(a.length !== a[0].length){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(a)}\n'abs()' only accepts array with similar dimensions!\n`);
+	}
+        return Math.abs(det(a, a.length));
+};
+
+const absComplex = (a) => {
+        return parseFloat(Math.sqrt(Math.pow(a.re , 2) + Math.pow(a.im , 2)).toFixed(2));
+};
+
+exports.abs = (...args) => {
+	if(args.length !== 1){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n'abs()' only accepts only one parameter!\n`);
+	}
+	validate(args);
+        return abs(args[0]);
+};
diff --git a/src/addition/index.js b/src/addition/index.js
new file mode 100644
index 0000000..c55fab0
--- /dev/null
+++ b/src/addition/index.js
@@ -0,0 +1,85 @@
+/*Addition for all datatypes and data-structures
+*Function: M.add(...args)
+*/
+const Complex = require('../complex');
+const validate = require('../validation/argument-length');
+
+const add = (...args) => {
+	switch(args[0].constructor){
+	case Number:
+		return  addNum(...args);
+	case String:
+		return addString(...args);
+	case Array:
+		if(args[0][0].constructor === Array){
+			return args.reduce((prev, next) =>
+					addMatrix(prev, next));
+		}
+		else{
+			 return args.reduce((prev, next) =>
+					addArray(prev, next));
+		}
+	case Complex:
+		return addComplex(...args);
+	}
+};
+
+const addNum = (...args) => {
+	let sum = 0;
+	args.forEach((e) => {
+		sum += e;
+	});
+	return sum;
+};
+
+const addString = (...args) => {
+	let sum = 0;
+	args.forEach((e) => {
+		sum += Number(e);
+	});
+	sum = sum.toString(10);
+	return sum;
+};
+
+const addArray = (a,b) => {
+	let sum = new Array(b.length);
+	for(let i = 0; i < b.length; i++){
+		let l = a[i] + b[i];
+		sum.push(l);
+		sum = sum.filter(n => n);
+	}
+	return sum;
+};
+
+const addMatrix = (a,b) => {
+	let sum = [...Array(b.length)].map(x => Array(b[0].length).fill(0));
+	for(let i = 0; i < b.length; i++){
+		for(let j = 0; j < b[0].length; j++){
+
+			sum[i][j] = a[i][j] + b[i][j];
+		}
+	}
+	return sum;
+};
+
+const addComplex = (...args) => {
+	let sum = {
+		re: 0,
+		im: 0
+		};
+	args.forEach((e) => {
+		sum.re += e.re;
+		sum.im += e.im;
+	});
+	return sum;
+};
+
+exports.add = (...args) => {
+	if(args.length <= 1){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'add()' only accepts 2 or more parameters!\n`);
+	}
+	else {
+	validate(args);
+	}
+	return add(...args);
+};
diff --git a/src/division/index.js b/src/division/index.js
new file mode 100644
index 0000000..faedc35
--- /dev/null
+++ b/src/division/index.js
@@ -0,0 +1,174 @@
+/*Division operation across all data-types and data-structures
+* Function: M.div(m,n)
+*/
+const Complex = require('../complex');
+const validate = require('../validation/argument-length');
+
+const div = (a,b) => {
+	switch(a.constructor){
+	case Number:
+		return divNum(a,b);
+	case String:
+		return divString(a,b);
+	case Array:
+		if(a[0].constructor === Array){
+			return	divMatrix(a,b);
+		}
+		else{
+			return divArray(a,b);
+		}
+	case Complex:
+		return divComplex(a,b);
+	}
+};
+
+const divNum = (a,b) => {
+	return a / b;
+};
+
+const divString = (a,b) => {
+	let div = Number(a) / Number(b);
+	return div.toString(10);
+};
+
+const divArray = (a,b) => {
+	let div = new Array(a.length);
+	for(let i = 0; i < a.length; i++){
+		let l = a[i] / b[i];
+		div.push(l);
+		div = div.filter(n => n);
+	}
+	return div;
+};
+
+//Determinant of a matrix
+
+function det(a,n){
+	let determinant = 0, c1, c2, sign =  1;
+	let detArr = [...Array(n)].map(x => Array(n).fill(0));
+	if(n === 1){
+		return a[0][0];
+	}
+	else if(n === 2){
+		determinant = a[0][0]*a[1][1]- a[0][1]*a[1][0];
+	return determinant;
+	}
+	else{
+		for(let i = 0; i < n; i++){
+			c1 = 0, c2 = 0;
+			for(let j = 0; j < n; j++){
+			for(let k = 0; k < n; k++){
+				if(j != 0 && k != i){
+					detArr[c1][c2] = a[j][k];
+					c2++;
+					if(c2 > n - 2){
+					c1++;
+					c2 = 0;
+					}
+				}
+			}
+		}
+		determinant = determinant + sign * a[0][i] * det(detArr, n - 1);
+		sign = -1 * sign;
+		}
+		return determinant;
+	}
+}
+function coFactor(a,temp, p, q, n) {
+	let i = 0, j = 0;
+	for(let row = 0; row < n; row++){
+		for(let col = 0; col < n; col++){
+			if(row !== p && col != q){
+				temp[i][j++] = a[row][col];
+			if(j === n - 1){
+				j = 0;
+				i++;
+				}
+			}
+		}
+	}
+}
+function _adjugate(a){
+	let n = a.length;
+	let adj = [...Array(n)].map(x => Array(n).fill(0));
+	let temp = [...Array(n)].map(x => Array(n).fill(0));
+	if(n === 1){
+		return 1;
+	}
+
+	let sign = 1;
+
+	for(let i = 0; i < n; i++){
+		for(let j = 0; j < n; j++){
+
+			coFactor(a,temp,i,j,n);
+			sign = ((i + j) % 2 === 0 ? 1: -1);
+			adj[j][i] = sign * det(temp, n - 1);
+		}
+	}
+	return(adj);
+}
+
+function inverse(a){
+	let n = a.length;
+	let determinant = det(a, n);
+	if(determinant === 0){
+		return 0;
+	}
+	let inv = [...Array(n)].map(x => Array(n).fill(0));
+	let adj = _adjugate(a);
+
+	if(adj === 1){
+		return 1;
+	}
+
+	for(let i = 0; i < n; i++){
+		for(let j = 0; j < n; j++){
+			inv[i][j] = Number(parseFloat(adj[i][j]/determinant).toFixed(2));
+		}
+	}
+	return inv;
+}
+
+const divMatrix = (a,b) => {
+	b = inverse(b);
+	if(b === 0){
+		return 0;
+	}
+
+	if(b === 1){
+		return 1;
+	}
+
+        let div = [...Array(a.length)].map(x => Array(a[0].length).fill(0));
+	for(let i = 0; i < a.length; i++){
+		for(let j = 0; j < b.length; j++){
+			let sum = 0;
+			for(let k = 0; k < a[0].length; k++){
+				let pro = a[i][k] * b[k][j];
+				sum = Math.round(sum + pro);
+			}
+		div[i][j] = sum;
+		}
+	}
+	return div;
+};
+
+const divComplex = (a,b) => {
+        let div = {
+                re: 0,
+                im: 0
+                };
+	let dm = Math.pow(b.re, 2) + Math.pow(b.im, 2);
+        div.re = parseFloat(((a.re * b.re + a.im * b.re)/dm).toFixed(2));
+	div.im = parseFloat(((b.re * a.im - a.re * b.im)/dm).toFixed(2));
+        return div;
+};
+
+exports.div = (...args) => {
+	if(args.length > 2){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n'div()' only accepts two parameters!\n`);
+	}
+	validate(args);
+        return div(args[0], args[1]);
+};
diff --git a/src/index.js b/src/index.js
index aaf2145..5b8c11a 100644
--- a/src/index.js
+++ b/src/index.js
@@ -34,6 +34,11 @@ const avg = require('./avg'),
     count = require('./count'),
     frequency = require('./frequency'),	
     gcd = require('./gcd'),
+	add = require('./addition'),
+	sub = require('./subtraction'),
+	mul = require('./multiplication'),
+	div = require('./division'),
+	abs = require('./absolute'),
 	isEven = require('./isEven'),
 	isOdd = require('./isOdd'),
 	lcm = require('./lcm'),
@@ -76,6 +81,11 @@ module.exports = {
 	permutation:permutation.permutation,
 	findPrimeFactors: findPrimeFactors.findPrimeFactors,
 	gcd,
+	add: add.add,
+	sub: sub.sub,
+	mul: mul.mul,
+	div: div.div,
+	abs: abs.abs,
 	isHarshad: harshad.isHarshad,
 	isEven,
 	isOdd,
diff --git a/src/multiplication/index.js b/src/multiplication/index.js
new file mode 100644
index 0000000..009cbd0
--- /dev/null
+++ b/src/multiplication/index.js
@@ -0,0 +1,74 @@
+/*Multiplication across all data-types and data-structures
+*Function: M.mul(m,n)
+*/
+const Complex = require('../complex');
+const validate = require('../validation/argument-length');
+
+const mul = (a,b) => {
+	switch(a.constructor){
+	case Number:
+		return mulNum(a,b);
+	case String:
+		return mulString(a,b);
+	case Array:
+		if(a[0].constructor === Array){
+			return	mulMatrix(a,b);
+		}
+		else{
+			 return mulArray(a,b);
+		}
+	case Complex:
+		return mulComplex(a,b);
+	}
+};
+
+const mulNum = (a,b) => {
+	return a * b;
+};
+
+const mulString = (a,b) => {
+	let pro = Number(a) * Number(b);
+	return pro.toString(10);
+};
+
+const mulArray = (a,b) => {
+	let pro = new Array(a.length);
+	for(let i = 0; i < a.length; i++){
+		let l = a[i] * b[i];
+		pro.push(l);
+		pro = pro.filter(n => n);
+	}
+	return pro;
+};
+
+const mulMatrix = (a,b) => {
+        let pro = [...Array(b.length)].map(x => Array(b[0].length).fill(0));
+        for(let i = 0; i < a.length; i++){
+                for(let j = 0; j < b[0].length; j++){
+			let sum = 0;
+			for(let k = 0; k < a[0].length; k++){
+				sum += a[i][k] * b[k][j];
+			}
+			pro[i][j] = sum;
+                }
+        }
+        return pro;
+};
+
+const mulComplex = (a,b) => {
+        let pro = {
+                re: 0,
+                im: 0
+                };
+        pro.re = a.re * b.re;
+	pro.im = a.im * b.im;
+        return pro;
+};
+
+exports.mul = (...args) => {
+	if(args.length > 2){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n'mul()' only accepts two parameters!\n`);
+	}
+	validate(args);
+        return mul(args[0], args[1]);
+};
diff --git a/src/subtraction/index.js b/src/subtraction/index.js
new file mode 100644
index 0000000..37fc53d
--- /dev/null
+++ b/src/subtraction/index.js
@@ -0,0 +1,71 @@
+/*Subtraction across all data-types and data-structures
+*Function: M.sub(m,n)
+*/
+const Complex = require('../complex');
+const validate = require('../validation/argument-length');
+
+const subNum = (a,b) => {
+	return a - b;
+};
+
+const subString = (a,b) => {
+	let diff = Number(a) - Number(b);
+	return diff.toString(10);
+};
+
+const subArray = (a,b) => {
+	let diff = new Array(a.length);
+	for(let i = 0; i < a.length; i++){
+		let l = a[i] - b[i];
+		diff.push(l);
+		diff = diff.filter(n => n);
+	}
+	return diff;
+};
+
+const subMatrix = (a,b) => {
+        let diff = [...Array(b.length)].map(x => Array(b[0].length).fill(0));
+        for(let i = 0; i < b.length; i++){
+                for(let j = 0; j < b[0].length; j++){
+
+                       diff[i][j] = a[i][j] - b[i][j];
+                }
+        }
+        return diff;
+};
+
+const subComplex = (a,b) => {
+        let diff = {
+                re: 0,
+                im: 0
+                };
+        diff.re = a.re - b.re;
+	diff.im = a.im - b.im;
+        return diff;
+};
+
+const sub = (a,b) => {
+	switch(a.constructor){
+	case Number:
+		return  subNum(a,b);
+	case String:
+		return subString(a,b);
+	case Array:
+		if(a[0].constructor === Array){
+			return	subMatrix(a,b);
+		}
+		else {
+			 return subArray(a,b);
+		}
+	case Complex:
+		return subComplex(a,b);
+	}
+};
+
+exports.sub = (...args) => {
+	if(args.length > 2){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n'sub()' only accepts two parameters!\n`);
+	}
+	validate(args);
+        return sub(args[0], args[1]);
+};
diff --git a/src/validation/argument-length.js b/src/validation/argument-length.js
new file mode 100644
index 0000000..9d2f28f
--- /dev/null
+++ b/src/validation/argument-length.js
@@ -0,0 +1,69 @@
+/*
+* Argument and Length validation
+*/
+const Complex = require('../complex');
+module.exports = (...args) => {
+	if(args[0][0].constructor === Number){
+		for(let i = 0; i < args[0].length; i++){
+				if(typeof args[0][i] !== 'number'){
+					throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n, 'function' only accepts parameters of similar types!\n`)
+			}
+		}
+	}
+	else if(args[0][0].constructor === String){
+		for(let i = 0; i < args[0].length; i++){
+			if(typeof args[0][i] !== 'string'){
+				throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'function' only accepts parameters of similar types!\n`);
+			}
+		}
+	}
+	else if(args[0][0].constructor === Array){
+		let arr = args[0];
+		if(arr[0][0].constructor === Array){
+			let len = arr[0][0].length;
+			for(let i = 0; i < arr.length; i++){
+				for(let j = 0; j < arr[0].length; j++){
+					if(arr[i][j].length !== len){
+						throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'function' only accepts parameters of similar length!\n`);
+					}
+				}
+			}
+			for(let i = 0; i < arr.length; i++){
+				for(let j = 0 ;j< arr[0].length; j++){
+					for(let k = 0; k < arr[0][0].length; k++){
+						if(typeof arr[i][j][k] !== 'number'){
+							throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'function' only accepts parameters of similar types!\n`);
+						}
+					}
+				}
+			}
+		}
+		else{
+			for(let i = 0; i < arr.length; i++){
+				for(let j = 0; j < arr.length; j++){
+					if(arr[i].length !== arr[j].length){
+						throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'function' only accepts parameters of similar length!\n`);
+					}
+				}
+			}
+			for(let i = 0; i < arr.length; i++){
+				for(let j = 0; j < arr[0].length; j++){
+					if(typeof arr[i][j] !== 'number'){
+						throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'function' only accepts parameters of similar types!\n`);
+					}
+				}
+			}
+		}
+
+	}
+	else if(args[0][0].constructor === Complex){
+		for(let i = 0; i < args[0].length; i++){
+			if(args[0][i].constructor !== Complex){
+				throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n 'function' only accepts parameters of similar types!\n`);
+			}
+		}
+	}
+	else{
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(args)}\n`);
+	}
+};//End of module exports


Test patch:
diff --git a/test/absolute-spec.js b/test/absolute-spec.js
new file mode 100644
index 0000000..627e583
--- /dev/null
+++ b/test/absolute-spec.js
@@ -0,0 +1,75 @@
+const assert = require('assert'),
+	abs = require('../src/absolute').abs,
+	Complex = require('../src/complex'),
+	a = new Complex(7,3),
+	b = new Complex(3,4);
+
+describe('[Function: abs]', () => {
+	it('should return a function', () => {
+		assert.strictEqual(typeof abs, 'function');
+	});
+
+	it('should throw a TypeError if no parameter is passed', () => {
+		assert.throws(() => abs(), TypeError);
+	});
+
+	it('should throw a TypeError when two parameters are passed', () => {
+		assert.throws(() => abs(1,2), TypeError);
+	});
+
+	it('should return 14 when -14 is passed', () => {
+		assert.strictEqual(abs(-14), 14);
+	});
+
+	it('should return 12.24 when -12.24 is passed', () => {
+		assert.strictEqual(abs(-12.24), 12.24);
+	});
+
+	it('should throw an error when (1,2,4) is passed', () => {
+		assert.throws(() => abs(1,2,4), TypeError);
+	});
+
+	it('should return "20" when string "-20" is passed', () => {
+		assert.strictEqual(abs('-20'), "20");
+	});
+
+	it('should return 0 when [12,9] is passed', () => {
+		assert.deepStrictEqual(abs([12,9]), 0);
+	});
+
+	it('should return 2 when [[2]] is passed', () => {
+		assert.strictEqual(abs([[2]]), 2);
+	});
+
+	it('should return 12 when ([[3,2],[5,4]]) is passed', () => {
+		assert.deepStrictEqual(abs([[3,2],[5,4]]), 2);
+	});
+
+	it('should return 306 when [[6,1,1],[4,-2,5],[2,8,7]] is passed', () => {
+		assert.strictEqual(abs([[6,1,1],[4,-2,5],[2,8,7]]), 306);
+	});
+
+	it('should return 7.62 when Complex objects a are passed', () => {
+		assert.deepStrictEqual(abs(a), 7.62);
+	});
+
+	it('should return 5 when Complex object b is passed', () => {
+		assert.strictEqual(abs(b), 5);
+	});
+
+	it('should throw an error when boolean values are passed', () => {
+		assert.throws(() => abs(false), TypeError);
+ 	});
+
+	it('should throw an error when wrong dimensions of matrix is passed [[1,2,3,4],[1,2,3,4]]', () => {
+		assert.throws(() => abs([[1,2,3,4],[1,2,3,4]]), TypeError);
+});
+
+	it('should return 5 when 5 is passed', () => {
+		assert.strictEqual(abs(5), 5);
+	});
+
+	it('should return "9" when "9" is passed', () => {
+		assert.strictEqual(abs('9'), "9");
+	});
+});
diff --git a/test/addition-spec.js b/test/addition-spec.js
new file mode 100644
index 0000000..d64ac81
--- /dev/null
+++ b/test/addition-spec.js
@@ -0,0 +1,97 @@
+const assert = require('assert'),
+	add = require('../src/addition').add,
+	Complex = require('../src/complex'),
+	a = new Complex(7,3),
+	b = new Complex(4,6);
+
+describe('[Function: add]', () => {
+	it('should return a function', () => {
+		assert.strictEqual(typeof add, 'function');
+	});
+
+	it('should throw a TypeError if no parameter is passed', () => {
+		assert.throws(() => add(), TypeError);
+	});
+
+	it('should throw a TypeError when one parameter is passed', () => {
+		assert.throws(() => add([1,2,3,4]), TypeError);
+	});
+
+	it('should return -6 when (-2,-4 is passed', () => {
+		assert.strictEqual(add(-2,-4), -6);
+	});
+
+	it('should return 15 when (1,2,3,4,5) is passed', () => {
+		assert.strictEqual(add(1,2,3,4,5), 15);
+	});
+
+	it('should return 12.2 when (1.2,4.5,6.5) is passed', () => {
+		assert.strictEqual(add(1.2,4.5,6.5), 12.2);
+	});
+
+	it('should return 15 when strings (1,2,3,4,5) is passed', () => {
+		assert.strictEqual(add('1','2','3','4','5'), "15");
+	});
+
+	it('should return [2,4,6,8,10] when [1,2,3,4,5],[1,2,3,4,5] is passed', () => {
+		assert.deepStrictEqual(add([1,2,3,4,5],[1,2,3,4,5]), [2,4,6,8,10]);
+	});
+
+	it('should return [3,6,9,12,15] when [1,2,3,4,5] is passed thrice', () => {
+		assert.deepStrictEqual(add([1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]), [3,6,9,12,15]);
+	});
+
+	it('should return [[14]] when ([[1]],[[5]],[[8]]) is passed', () => {
+		assert.deepStrictEqual(add([[1]], [[5]], [[8]]), [[14]]);
+	});
+
+	it('should return [[1,5],[10,6]] when [[1,2],[2,5]],[[0,3],[8,1]] is passed', () => {
+		assert.deepStrictEqual(add([[1,2],[2,5]],[[0,3],[8,1]]), [[1,5], [10,6]]);
+	});
+
+	it('should return an object when Complex objects a,b are passed', () => {
+		assert.deepStrictEqual(add(a,b), {re: 11, im: 9});
+	});
+
+	it('should throw an error when boolean values are passed', () => {
+		assert.throws(() => add(false, true, false), TypeError);
+	});
+
+	it('should throw an error when there is type difference', () => {
+		assert.throws(() => add(1,2,4,'6',7), TypeError);
+	});
+
+	it('should throw an error when there is type difference', () => {
+		assert.throws(() => add(1.2,1.4,[1,2,3],5.6), TypeError);
+	});
+
+	it('should throw an error when there is a type difference', () => {
+		assert.throws(() => add('1','2', 3, '4'), TypeError);
+	});
+
+	it('should throws an error when the object is not of Complex', () => {
+		assert.throws(() => add(a,{p: 30, r: 20}), TypeError);
+	});
+
+	it('should throw an error when no object match', () => {
+		assert.throws(() => add({p: 30, q: 20}, a, {r: 10, s: 5}), TypeError);
+	});
+
+	it('should throw an error when matrix has a length difference', () => {
+		assert.throws(() => add([[1]], [[1,2,3]], [[8]]), TypeError);
+	});
+
+	it('should throw an error when matrix has a type difference', () => {
+		assert.throws(() => add([[2]], [['5']], [['8']]), TypeError);
+	});
+
+	it('should throw an error when 1D array has length difference', () => {
+		assert.throws(() => add([1,2,3,4,5],[1,2,3,4]), TypeError);
+	});
+
+	it('should throw an error when 1D array has type difference', () => {
+		assert.throws(() => add([1,2,3,'4',5],[1,2,3,4,5]), TypeError);
+	});
+
+	
+});
diff --git a/test/division-spec.js b/test/division-spec.js
new file mode 100644
index 0000000..e962ab7
--- /dev/null
+++ b/test/division-spec.js
@@ -0,0 +1,74 @@
+const assert = require('assert'),
+	div = require('../src/division').div,
+	Complex = require('../src/complex'),
+	a = new Complex(7,3),
+	b = new Complex(4,6);
+
+describe('[Function: div]', () => {
+	it('should return a function', () => {
+		assert.strictEqual(typeof div, 'function');
+	});
+	it('should throw a TypeError if no parameter is passed', () => {
+		assert.throws(() => div(), TypeError);
+	});
+	it('should throw a TypeError when one parameter is passed', () => {
+		assert.throws(() => div([1,2,3,4]), TypeError);
+	});
+	it('should return 1 when (4,2) is passed', () => {
+		assert.strictEqual(div(4,2), 2);
+	});
+	it('should return 4.2 when (8.4, 2.0) is passed', () => {
+		assert.strictEqual(div(8.4,2.0), 4.2);
+	});
+	it('should throw an error when (1,2,4) is passed', () => {
+		assert.throws(() => div(1,2,4), TypeError);
+	});
+	it('should return "4.2" when strings (8.4,2.0) is passed', () => {
+		assert.strictEqual(div('8.4','2.0'), "4.2");
+	});
+	it('should return [2,3] when [12,9],[6,3] is passed', () => {
+		assert.deepStrictEqual(div([12,9],[6,3]), [2,3]);
+	});
+	it('should return 0 if determinant is zero', () => {
+		assert.deepStrictEqual(div([[0,0]],[[0,0]]), 0);
+	});
+	it('should return 1 when 1x1 matrix is passed', () => {
+		assert.strictEqual(div([[4]],[[4]]), 1)
+	});
+	it('should return [[1,0],[0,1]] when ([[4,3],[3,2]],[[4,3], [3,2]]) is passed', () => {
+		assert.deepStrictEqual(div([[4,3],[3,2]], [[4,3],[3,2]]), [[1,0], [0,1]]);
+	});
+	it('should return [[1,-0,-0],[-0,1,-0],[-0,-0,1]] when same 3x3 matrix is passed', () => {
+		assert.deepStrictEqual(div([[4,7,2],[2,6,4],[1,2,3]], [[4,7,2],[2,6,4],[1,2,3]]), [[1,-0,-0],[-0,1,-0],[-0,-0,1]]);
+	});
+	it('should return an object when Complex objects a,b are passed', () => {
+		assert.deepStrictEqual(div(a,b), {re: 0.77, im: -0.58});
+	});
+	it('should throw an error when boolean values are passed', () => {
+		assert.throws(() => div(false, true), TypeError);
+ 	});
+	 it('should throw an error when there is type difference', () => {
+		assert.throws(() => div(1,'6'), TypeError);
+ 	});
+	 it('should throw an error when there is a type difference', () => {
+		assert.throws(() => div('1',3), TypeError);
+ 	});
+	 it('should throws an error when the object is not of Complex', () => {
+		assert.throws(() => div(a,{p: 30, r: 20}), TypeError);
+ 	});
+	 it('should throw an error when no object match', () => {
+		 assert.throws(() => div({p: 30, q: 20}, a), TypeError)
+ 	});
+	 it('should throw an error when matrix has a length difference', () => {
+		 assert.throws(() => div([[1]], [[1,2]]), TypeError);
+ 	});
+	 it('should throw an error when matrix has a type difference', () => {
+		 assert.throws(() => div([[1]], [['5']]), TypeError);
+ 	});
+	 it('should throw an error when 1D array has length difference', () => {
+		 assert.throws(() => div([1,2,3,4,5],[1,2,3,4]), TypeError);
+	});
+	 it('should throw an error when 1D array has type difference', () => {
+		assert.throws(() => div([1,2,3,'4',5],[1,2,3,4,5]), TypeError);
+	 });
+});
diff --git a/test/multiplication-spec.js b/test/multiplication-spec.js
new file mode 100644
index 0000000..33f97e4
--- /dev/null
+++ b/test/multiplication-spec.js
@@ -0,0 +1,68 @@
+const assert = require('assert'),
+	mul = require('../src/multiplication').mul,
+	Complex = require('../src/complex'),
+	a = new Complex(7,3),
+	b = new Complex(4,6);
+
+describe('[Function: mul]', () => {
+	it('should return a function', () => {
+		assert.strictEqual(typeof mul, 'function');
+	});
+	it('should throw a TypeError if no parameter is passed', () => {
+		assert.throws(() => mul(), TypeError);
+	});
+	it('should throw a TypeError when one parameter is passed', () => {
+		assert.throws(() => mul([1,2,3,4]), TypeError);
+	});
+	it('should return 2 when (1,2) is passed', () => {
+		assert.strictEqual(mul(1,2), 2);
+	});
+	it('should return 0.24 when (1.2, 0.2) is passed', () => {
+		assert.strictEqual(mul(1.2,0.2), 0.24);
+	});
+	it('should throw an error when (1,2,4) is passed', () => {
+		assert.throws(() => mul(1,2,4), TypeError);
+	});
+	it('should return "2" when strings (1,2) is passed', () => {
+		assert.strictEqual(mul('1','2'), "2");
+	});
+	it('should return [72,54] when [12,9],[6,6] is passed', () => {
+		assert.deepStrictEqual(mul([12,9],[6,6]), [72,54]);
+	});
+	it('should return [[4,4],[10,8]] when ([[1,2],[3,4]],[[2,0],[1,2]]) is passed', () => {
+		assert.deepStrictEqual(mul([[1,2],[3,4]], [[2,0],[1,2]]), [[4,4],[10,8]]);
+	});
+	it('should return an object when Complex objects a,b are passed', () => {
+		assert.deepStrictEqual(mul(a,b), {re: 28, im: 18});
+	});
+	it('should throw an error when boolean values are passed', () => {
+		assert.throws(() => mul(false, true), TypeError);
+ 	});
+	it('should throw an error when there is type difference', () => {
+		 assert.throws(() => mul(1,'6'), TypeError);
+	 });
+	it('should throw an error when there is a type difference', () => {
+		 assert.throws(() => mul('1',3), TypeError);
+ 	});
+	 it('should throws an error when the object is not of Complex', () => {
+		assert.throws(() => mul(a,{p: 30, r: 20}), TypeError);
+ 	});
+	 it('should throw an error when no object match', () => {
+		assert.throws(() => mul({p: 30, q: 20}, a), TypeError)
+ 	});
+	it('should throw an error when matrix has a length difference', () => {
+		assert.throws(() => mul([[1]], [[1,2]]), TypeError);
+ 	});
+	it('should throw an error when matrix has a type difference', () => {
+		 assert.throws(() => mul([[1]], [['5']]), TypeError);
+ 	});
+	it('should throw an error when 1D array has length difference', () => {
+		 assert.throws(() => mul([1,2,3,4,5],[1,2,3,4]), TypeError);
+	});
+	it('should throw an error when 1D array has type difference', () => {
+		 assert.throws(() => mul([1,2,3,'4',5],[1,2,3,4,5]), TypeError);
+	});
+	it('should return -80 when -8, 10 is passed', () => {
+		assert.strictEqual(mul(-8,10), -80);
+	});
+});
diff --git a/test/subtraction-spec.js b/test/subtraction-spec.js
new file mode 100644
index 0000000..0146025
--- /dev/null
+++ b/test/subtraction-spec.js
@@ -0,0 +1,68 @@
+const assert = require('assert'),
+	sub = require('../src/subtraction').sub,
+	Complex = require('../src/complex'),
+	a = new Complex(7,3),
+	b = new Complex(4,6);
+
+describe('[Function: sub]', () => {
+	it('should return a function', () => {
+		assert.strictEqual(typeof sub, 'function');
+	});
+	it('should throw a TypeError if no parameter is passed', () => {
+		assert.throws(() => sub(), TypeError);
+	});
+	it('should throw a TypeError when one parameter is passed', () => {
+		assert.throws(() => sub([1,2,3,4]), TypeError);
+	});
+	it('should return 1 when (1,2) is passed', () => {
+		assert.strictEqual(sub(1,2), -1);
+	});
+	it('should return 1.0 when (1.2, 0.2) is passed', () => {
+		assert.strictEqual(sub(1.2,0.2), 1.0);
+	});
+	it('should throw an error when (1,2,4) is passed', () => {
+		assert.throws(() => sub(1,2,4), TypeError);
+	});
+	it('should return -1 when strings (1,2) is passed', () => {
+		assert.strictEqual(sub('1','2'), "-1");
+	});
+	it('should return [6,3] when [12,9],[6,6] is passed', () => {
+		assert.deepStrictEqual(sub([12,9],[6,6]), [6,3]);
+	});
+	it('should return [[3]] when ([[8]],[[5]]) is passed', () => {
+		assert.deepStrictEqual(sub([[8]], [[5]]), [[3]]);
+	});
+	it('should return [[1,2]] when [[3,4]],[[2,2]] is passed', () => {
+		assert.deepStrictEqual(sub([[3,4]],[[2,2]]), [[1,2]]);
+	});
+	it('should return an object when Complex objects a,b are passed', () => {
+		assert.deepStrictEqual(sub(a,b), {re: 3, im: -3});
+	});
+	it('should throw an error when boolean values are passed', () => {
+		assert.throws(() => sub(false, true), TypeError);
+	});
+	it('should throw an error when there is type difference', () => {
+		 assert.throws(() => sub(1,'6'), TypeError);
+ 	});
+	it('should throw an error when there is a type difference', () => {
+		assert.throws(() => sub('1',3), TypeError);
+ 	});
+	it('should throws an error when the object is not of Complex', () => {
+		 assert.throws(() => sub(a,{p: 30, r: 20}), TypeError);
+ 	});
+	it('should throw an error when no object match', () => {
+		assert.throws(() => sub({p: 30, q: 20}, a), TypeError)
+ 	});
+	it('should throw an error when matrix has a length difference', () => {
+		assert.throws(() => sub([[1]], [[1,2]]), TypeError);
+ 	});
+	it('should throw an error when matrix has a type difference', () => {
+		 assert.throws(() => sub([[1]], [['5']]), TypeError);
+	});
+	it('should throw an error when 1D array has length difference', () => {
+		 assert.throws(() => sub([1,2,3,4,5],[1,2,3,4]), TypeError);
+	});
+	it('should throw an error when 1D array has type difference', () => {
+		assert.throws(() => sub([1,2,3,'4',5],[1,2,3,4,5]), TypeError);
+	});
+});