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 description:
Complex Numbers (#57)
*Added integer-object checking

*Added Complex Number function in index and readme

*Added unit tests in complex-spec

### 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**:#57

- *Give additional information regarding the PR below:*

------------


Patch:
diff --git a/README.md b/README.md
index d1e9108..c30e0bc 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ $ npm install mathball --save
 
 - **Range of Numbers** - [rangePrime][7] - [rangeFibonacci][8]
 
-- **Mathematical Utilities** - [frequency][40] - [gcd][10] - [isEven][11] - [isOdd][12] - [lcm][13] - [length][14] - [max][15] - [min][16] - [modInv][39] - [sort][17] - [sum][18] - [pow][46]
+- **Mathematical Utilities** - [frequency][40] - [gcd][10] - [isEven][11] - [isOdd][12] - [lcm][13] - [length][14] - [max][15] - [min][16] - [modInv][39] - [sort][17] - [sum][18] - [pow][46] - [Complex][57]
 
 - **Data Structures** - [priorityQueue][44]
 
@@ -111,4 +111,5 @@ The MIT License 2019 - [Priyabrata Biswas][20].
 [43]: https://github.com/pbiswas101/Mathball/blob/master/src/carmichael/index.js
 [44]: https://github.com/pbiswas101/Mathball/blob/master/src/PriorityQueue/index.js
 [45]: https://github.com/pbiswas101/Mathball/blob/master/src/harshad/index.js
-[46]: https://github.com/pbiswas101/Mathball/blob/master/src/pow/index.js
\ No newline at end of file
+[46]: https://github.com/pbiswas101/Mathball/blob/master/src/pow/index.js
+[57]: https://github.com/pbiswas101/Mathball/blob/master/src/complex/index.js
diff --git a/src/complex/index.js b/src/complex/index.js
new file mode 100644
index 0000000..2a916aa
--- /dev/null
+++ b/src/complex/index.js
@@ -0,0 +1,80 @@
+/*Complex Numbers
+* Use: const a = new M.Complex(real, imaginery);
+*/
+const validate = require('../validation/integer-object');
+class Complex {
+    constructor(r,i) {
+        this.r = r;
+        this.i = i;
+        validate(this.r, 'Complex');
+        validate(this.i, 'Complex');
+    }
+    get re() {
+        return this.r;
+    }
+    get im(){
+        return this.i;
+    }
+    abs(){
+        return parseFloat(Math.sqrt(Math.pow(this.r , 2) + Math.pow(this.i , 2)).toFixed(2));
+    }
+    conjugate(){
+        let img = -this.i;
+        const obj = new Complex(this.r, img);
+        return obj;
+    }
+    get conj(){
+        return this.conjugate();
+    }
+    add(args){
+        validate(args, 'add');
+        if(Number.isInteger(args)){
+            let obj = new Complex(this.r + args, this.i);
+            return obj;
+        }
+        else{
+            let obj = new Complex(this.r + args.r, this.i + args.i);
+            return obj;
+        }
+    }
+    sub(args){
+        validate(args, 'sub');
+        if(Number.isInteger(args)){
+            let obj = new Complex(this.r - args, this.i);
+            return obj;
+        }
+        else{
+            let obj = new Complex(this.r - args.r, this.i - args.i);
+            return obj;
+            }
+        }
+    multiply(args){
+        validate(args, 'multiply');
+        if(Number.isInteger(args)){
+            let obj = new Complex(this.r * args, this.i * args);
+            return obj;
+        }
+        else{
+            let obj = new Complex((this.r * args.r - this.i * args.i),
+                        ( this.r * args.i + args.r * this.i));
+            return obj;
+            }
+    }
+    divide(args){
+        validate(args, 'divide');
+        if(Number.isInteger(args)){
+            let obj = new Complex(parseFloat(this.r/args),
+                         parseFloat(this.i/args));
+            return obj;
+        }
+        else {
+        let dm = Math.pow(args.r, 2) + Math.pow(args.i , 2);
+        let real = parseFloat(((this.r * args.r + this.i * args.im)/dm).toFixed(2));
+        let img = parseFloat(((args.r * this.i - this.r * args.i)/dm).toFixed(2));
+        let obj = new Complex(real, img);
+        return obj;
+        }
+
+    }
+}
+module.exports = Complex;
diff --git a/src/index.js b/src/index.js
index 770ef9a..fbef2ed 100644
--- a/src/index.js
+++ b/src/index.js
@@ -33,7 +33,8 @@ const frequency = require('./frequency'),
 	modInv = require('./modInv'),
 	pow = require('./pow'),
 	sort = require('./sort'),
-	sum = require('./sum');
+	sum = require('./sum'),
+	Complex = require('./complex');
 
 /* Helper Methods */
 const performance = require('./performance'),
@@ -79,5 +80,6 @@ module.exports = {
 	isDeficient,
 	PriorityQueue,
 	isCarmichael: carmichael.isCarmichael,
-	rangeFibonacci: fibonacci.rangeFibonacci
+	rangeFibonacci: fibonacci.rangeFibonacci,
+	Complex
 };
diff --git a/src/validation/integer-object.js b/src/validation/integer-object.js
new file mode 100644
index 0000000..41c235c
--- /dev/null
+++ b/src/validation/integer-object.js
@@ -0,0 +1,7 @@
+//validate integer or object
+
+module.exports = (arg, func) =>  {
+	if(typeof arg === 'boolean' || typeof arg === 'string' || arg.constructor === Array){
+		throw new TypeError(`Invalid argument received: ${JSON.stringify(arg)}\n'${func}()' only accepts an integer or an object!\n`);
+	}
+}


Test patch:
diff --git a/test/complex-spec.js b/test/complex-spec.js
new file mode 100644
index 0000000..4fde58f
--- /dev/null
+++ b/test/complex-spec.js
@@ -0,0 +1,135 @@
+const assert = require('assert'),
+Complex = require('../src/complex'),
+a = new Complex(3,2),
+b = new Complex(2,1),
+conjugate = a.conj,
+add1 = a.add(5),
+add2 = a.add(b),
+sub1 = a.sub(1),
+sub2 = a.sub(b),
+mul = a.multiply(b),
+mul1 = a.multiply(4),
+div = a.divide(b),
+div1 = a.divide(3);
+
+describe('[Function: complex]', () => {
+	it('should be an object', () => {
+			assert.strictEqual(typeof a, 'object');
+
+			});
+
+	it('should return 3 when a.re is called', () => {
+			assert.strictEqual(a.re, 3);
+			});
+
+	it('should return 2 when a.im is called', () => {
+			assert.strictEqual(a.im, 2);
+			});
+
+	it('should return something when a.abs() is called', () => {
+			assert.strictEqual(a.abs(), 3.61);
+			});
+
+	it('should return an object when a.add(5) is called', () => {
+			assert.strictEqual(typeof add1, 'object');
+			});
+
+	it('should return 8 when add1.re is called', () => {
+			assert.strictEqual(add1.re, 8);
+			});
+
+	it('should return an object when a.add(b) is called', () => {
+			assert.strictEqual(typeof add2, 'object');
+			});
+
+	it('should return 5 when add2.re is called', () => {
+			assert.strictEqual(add2.re, 5);
+			});
+
+	it('should return 3 when add2.im is called', () => {
+			assert.strictEqual(add2.im, 3);
+			});
+
+	it('should return an object when a.conj is called', () => {
+			assert.strictEqual(typeof conjugate, 'object');
+			});
+
+	it('should return -2 if conjugate.im is called', () => {
+			assert.strictEqual(conjugate.im, -2);
+			});
+
+	it('should return 3 when conjugate.re is called', () => {
+			assert.strictEqual(conjugate.re, 3);
+			});
+
+	it('should return an object when a.sub(1) is called', () => {
+			assert.strictEqual(typeof sub1, 'object');
+			});
+
+	it('should return 2 when sub1.re is called', () => {
+			assert.strictEqual(sub1.re , 2);
+			});
+
+	it('should return 2 when sub1.im is called', () => {
+			assert.strictEqual(sub1.im, 2);
+			});
+
+	it('should return an object when a.sub(b) is called', () => {
+			assert.strictEqual(typeof sub2, 'object');
+			});
+
+	it('should return 1 when sub2.re is called', () => {
+			assert.strictEqual(sub2.re, 1);
+			});
+
+	it('should return 1 when sub2.im is called', () => {
+			assert.strictEqual(sub2.im, 1);
+			});
+
+	it('should return an object when a.multiply(b) is called', () => {
+			assert.strictEqual(typeof mul, 'object');
+			});
+
+	it('should return 4 when mul.re is called', () => {
+			assert.strictEqual(mul.re, 4);
+			});
+
+	it('should return 7 when mul.im is called', () => {
+			assert.strictEqual(mul.im, 7);
+			});
+
+	it('should return 12 when mul1.re is called', () => {
+			assert.strictEqual(mul1.re, 12);
+			});
+
+	it('should return an object when a.divide(b) is called', () => {
+			assert.strictEqual(typeof a.divide(b), 'object');
+			});
+
+	it('should return 1.6 when div.re is called', () => {
+			assert.strictEqual(div.re, 1.6);
+			});
+
+	it('should return 0.2 when div.im is called', () => {
+			assert.strictEqual(div.im, 0.2);
+			});
+
+	it('should return 1 when div1.re is called', () => {
+		assert.strictEqual(div1.re, 1);
+	});
+
+	it('should throw an error when argument passed is string', () => {
+			assert.throws(() => {
+					const an = new Complex("4", "3");
+					}
+					, TypeError);
+			});
+
+	it('should throw an error when a non-number is passed', () => {
+		assert.throws(() => {
+				const b = new Complex(2,4);
+				b.add([3]);
+					}
+					, TypeError);
+	});
+});