Add multiplyDigits and friends
authorGreg Hurrell <greg@hurrell.net>
Sat, 1 Aug 2015 00:43:08 +0000 (17:43 -0700)
committerGreg Hurrell <greg@hurrell.net>
Sat, 1 Aug 2015 00:43:08 +0000 (17:43 -0700)
.babelrc
src/__tests__/multiplyDigits-test.js [new file with mode: 0644]
src/add.js
src/addDigits.js [new file with mode: 0644]
src/getDigits.js [new file with mode: 0644]
src/multiplyDigits.js [new file with mode: 0644]

index ce840ab86460878600ba8b3dcc3ab29e877e6ba2..019f402363aaa4970d80c1079a96916bcfc9feb8 100644 (file)
--- a/.babelrc
+++ b/.babelrc
@@ -1,3 +1,8 @@
 {
-  "stage": 0
-}
\ No newline at end of file
+  "optional": [
+    "es7.asyncFunctions",
+    "es7.classProperties",
+    "es7.decorators",
+    "es7.objectRestSpread"
+  ]
+}
diff --git a/src/__tests__/multiplyDigits-test.js b/src/__tests__/multiplyDigits-test.js
new file mode 100644 (file)
index 0000000..b2de7e1
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2015-present Greg Hurrell. All rights reserved.
+ * Licensed under the terms of the MIT license.
+ */
+
+'use strict';
+
+import multiplyDigits from '../multiplyDigits';
+
+describe('multiplyDigits()', () => {
+  it('multiplies by 0', () => {
+    expect(multiplyDigits([1], 0, 2)).toEqual([0]);
+    expect(multiplyDigits([5], 0, 8)).toEqual([0]);
+    expect(multiplyDigits([4], 0, 10)).toEqual([0]);
+    expect(multiplyDigits([12], 0, 16)).toEqual([0]);
+  });
+
+  it('multiplies by 1', () => {
+    expect(multiplyDigits([1], 1, 2)).toEqual([1]);
+    expect(multiplyDigits([5], 1, 8)).toEqual([5]);
+    expect(multiplyDigits([4], 1, 10)).toEqual([4]);
+    expect(multiplyDigits([12], 1, 16)).toEqual([12]);
+  });
+
+  it('multiplies by 2', () => {
+    expect(multiplyDigits([1], 2, 2)).toEqual([0, 1]);
+    expect(multiplyDigits([5], 2, 8)).toEqual([2, 1]);
+    expect(multiplyDigits([4], 2, 10)).toEqual([8]);
+    expect(multiplyDigits([12], 2, 16)).toEqual([8, 1]);
+  });
+
+  it('multiplies by 100', () => {
+    expect(multiplyDigits([1], 100, 2)).toEqual([0, 0, 1, 0, 0, 1, 1]);
+    expect(multiplyDigits([5], 100, 8)).toEqual([4, 6, 7]);
+    expect(multiplyDigits([4], 100, 10)).toEqual([0, 0, 4]);
+    expect(multiplyDigits([12], 100, 16)).toEqual([0, 11, 4]);
+  });
+});
index fe31aa673c601327901e5fc490ad133cd8a0fb0f..fbf49d6ed597f513b13428f808aca087152f7d21 100644 (file)
@@ -7,41 +7,8 @@
 
 'use strict';
 
-/**
- * Strips the leading prefix from `number` in `base` and returns the remaining
- * part of the string.
- *
- * - "0x" (or "0X") for hexadecimal numbers.
- * - "0" for octal numbers.
- *
- * For all bases, leading whitespace is stripped.
- */
-function stripPrefix(number: string, base: number): string {
-  if (base === 16) {
-    return number.replace(/^\s*0x/i, '');
-  } else if (base === 8) {
-    return number.replace(/^\s*0/, '');
-  } else {
-    return number.replace(/^\s*/, '');
-  }
-}
-
-/**
- * Breaks the string repsentation of `number` in `base` into an array of decimal
- * digits (from least significant to most significant) for easier manipulation.
- *
- * For example, the hexadecimal representation `"40fa"` becomes `[10, 15, 0,
- * 4]`.
- */
-function getDigits(number: string, base: number): Array<number> {
-  return stripPrefix(number, base).trim().split('').reverse().map(digit => {
-    const result = parseInt(digit, base);
-    if (isNaN(result)) {
-      throw new Error('Invalid digit `' + digit + '` for base `' + base + '`');
-    }
-    return result;
-  });
-}
+import addDigits from './addDigits';
+import getDigits from './getDigits';
 
 /**
  * Adds two numbers `a` and `b`, both in `base` and returns the answer as a
@@ -50,18 +17,8 @@ function getDigits(number: string, base: number): Array<number> {
 export default function add(a: string, b: string, base: number): string {
   const aDigits = getDigits(a, base);
   const bDigits = getDigits(b, base);
-  let result = '';
-  let carry = 0;
-  for (
-    let i = 0, max = Math.max(aDigits.length, bDigits.length);
-    i < max || carry;
-    i++
-  ) {
-    const aDigit = aDigits[i] || 0;
-    const bDigit = bDigits[i] || 0;
-    const sum = aDigit + bDigit + carry;
-    result = (sum % base).toString(base) + result;
-    carry = Math.floor(sum / base);
-  }
-  return result ? result : '0';
+  return addDigits(aDigits, bDigits, base)
+    .reverse()
+    .map(number => number.toString(base))
+    .join('');
 }
diff --git a/src/addDigits.js b/src/addDigits.js
new file mode 100644 (file)
index 0000000..4a3de34
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2015-present Greg Hurrell. All rights reserved.
+ * Licensed under the terms of the MIT license.
+ *
+ * @flow
+ */
+
+'use strict';
+
+export default function addDigits(
+  aDigits: Array<number>,
+  bDigits: Array<number>,
+  base: number
+): Array<number> {
+  let result = [];
+  let carry = 0;
+  for (
+    let i = 0, max = Math.max(aDigits.length, bDigits.length);
+    i < max || carry;
+    i++
+  ) {
+    const aDigit = aDigits[i] || 0;
+    const bDigit = bDigits[i] || 0;
+    const sum = aDigit + bDigit + carry;
+    result.push(sum % base);
+    carry = Math.floor(sum / base);
+  }
+  return result.length ? result : [0];
+}
diff --git a/src/getDigits.js b/src/getDigits.js
new file mode 100644 (file)
index 0000000..fc8888d
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2015-present Greg Hurrell. All rights reserved.
+ * Licensed under the terms of the MIT license.
+ *
+ * @flow
+ */
+
+'use strict';
+
+/**
+ * Strips the leading prefix from `number` in `base` and returns the remaining
+ * part of the string.
+ *
+ * - "0x" (or "0X") for hexadecimal numbers.
+ * - "0" for octal numbers.
+ *
+ * For all bases, leading whitespace is stripped.
+ */
+function stripPrefix(number: string, base: number): string {
+  if (base === 16) {
+    return number.replace(/^\s*0x/i, '');
+  } else if (base === 8) {
+    return number.replace(/^\s*0/, '');
+  } else {
+    return number.replace(/^\s*/, '');
+  }
+}
+
+/**
+ * Breaks the string repsentation of `number` in `base` into an array of decimal
+ * digits (from least significant to most significant) for easier manipulation.
+ *
+ * For example, the hexadecimal representation `"40fa"` becomes `[10, 15, 0,
+ * 4]`.
+ */
+export default function getDigits(number: string, base: number): Array<number> {
+  return stripPrefix(number, base).trim().split('').reverse().map(digit => {
+    const result = parseInt(digit, base);
+    if (isNaN(result)) {
+      throw new Error('Invalid digit `' + digit + '` for base `' + base + '`');
+    }
+    return result;
+  });
+}
diff --git a/src/multiplyDigits.js b/src/multiplyDigits.js
new file mode 100644 (file)
index 0000000..afd2146
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015-present Greg Hurrell. All rights reserved.
+ * Licensed under the terms of the MIT license.
+ *
+ * @flow
+ */
+
+'use strict';
+
+import addDigits from './addDigits';
+
+/**
+ * Multiplication is repeated addition.
+ */
+export default function multiplyDigits(
+  multiplicand: Array<number>,
+  multiplier: number,
+  base: number
+): Array<number> {
+  let result = [0];
+  for (let i = 0; i < multiplier; i++) {
+    result = addDigits(result, multiplicand, base);
+  }
+  return result;
+}