Skip to content

Commit 6667e4c

Browse files
committed
Add BigInt version and push output chars to array
1 parent 9103435 commit 6667e4c

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

Conversions/ArbitraryBase.js

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const floorDiv = (dividend, divisor) => {
1212
}
1313

1414
/**
15-
* Converts a string from one base to other
15+
* Converts a string from one base to other. Loses accuracy above the value of `Number.MAX_SAFE_INTEGER`.
1616
* @param {string} stringInBaseOne String in input base
1717
* @param {string} baseOneCharacters Character set for the input base
1818
* @param {string} baseTwoCharacters Character set for the output base
@@ -43,14 +43,57 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
4343
value += (digitNumber * placeValue)
4444
placeValue *= stringOneBase
4545
}
46-
let stringInBaseTwo = ''
46+
const outputChars = []
4747
const stringTwoBase = baseTwoCharacters.length
4848
while (value > 0) {
4949
const [divisionResult, remainder] = floorDiv(value, stringTwoBase)
50-
stringInBaseTwo = baseTwoCharacters[remainder] + stringInBaseTwo
50+
outputChars.push(baseTwoCharacters[remainder])
5151
value = divisionResult
5252
}
53-
return stringInBaseTwo || baseTwoCharacters[0]
53+
return outputChars.reverse().join('') || baseTwoCharacters[0]
5454
}
5555

56-
export { convertArbitraryBase }
56+
/**
57+
* Converts a arbitrary-length string from one base to other. Doesn't lose accuracy.
58+
* @param {string} stringInBaseOne String in input base
59+
* @param {string} baseOneCharacters Character set for the input base
60+
* @param {string} baseTwoCharacters Character set for the output base
61+
* @returns {string}
62+
*/
63+
const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterString, baseTwoCharacterString) => {
64+
if ([stringInBaseOne, baseOneCharacterString, baseTwoCharacterString].map(arg => typeof arg).some(type => type !== 'string')) {
65+
throw new TypeError('Only string arguments are allowed')
66+
}
67+
68+
const baseOneCharacters = [...baseOneCharacterString]
69+
const baseTwoCharacters = [...baseTwoCharacterString]
70+
71+
for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) {
72+
if (charactersInBase.length !== new Set(charactersInBase).size) {
73+
throw new TypeError('Duplicate characters in character set are not allowed')
74+
}
75+
}
76+
const reversedStringOneChars = [...stringInBaseOne].reverse()
77+
const stringOneBase = BigInt(baseOneCharacters.length)
78+
let value = 0n
79+
let placeValue = 1n
80+
for (const digit of reversedStringOneChars) {
81+
const digitNumber = BigInt(baseOneCharacters.indexOf(digit))
82+
if (digitNumber === -1n) {
83+
throw new TypeError(`Not a valid character: ${digit}`)
84+
}
85+
value += (digitNumber * placeValue)
86+
placeValue *= stringOneBase
87+
}
88+
const outputChars = []
89+
const stringTwoBase = BigInt(baseTwoCharacters.length)
90+
while (value > 0n) {
91+
const divisionResult = value / stringTwoBase
92+
const remainder = value % stringTwoBase
93+
outputChars.push(baseTwoCharacters[remainder])
94+
value = divisionResult
95+
}
96+
return outputChars.reverse().join('') || baseTwoCharacters[0]
97+
}
98+
99+
export { convertArbitraryBase, convertArbitraryBaseBigIntVersion }

Conversions/test/ArbitraryBase.test.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { convertArbitraryBase } from '../ArbitraryBase'
1+
import { convertArbitraryBase, convertArbitraryBaseBigIntVersion } from '../ArbitraryBase'
22

33
test('Check the answer of convertArbitraryBase(98, 0123456789, 01234567) is 142', () => {
44
const res = convertArbitraryBase('98', '0123456789', '01234567')
@@ -44,3 +44,13 @@ test('zero', () => {
4444
const res = convertArbitraryBase('0', '0123456789', 'abc')
4545
expect(res).toBe('a')
4646
})
47+
48+
test('BigInt version with input string of arbitrary length', () => {
49+
const resBigIntVersion = convertArbitraryBaseBigIntVersion(
50+
String(10n ** 100n),
51+
'0123456789',
52+
'0123456789abcdefghijklmnopqrstuvwxyz'
53+
)
54+
55+
expect(resBigIntVersion).toBe((10n ** 100n).toString(36))
56+
})

0 commit comments

Comments
 (0)