-
-
Save ryasmi/91d7fd30710264affeb9 to your computer and use it in GitHub Desktop.
function convertBase(value, from_base, to_base) { | |
var range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split(''); | |
var from_range = range.slice(0, from_base); | |
var to_range = range.slice(0, to_base); | |
var dec_value = value.split('').reverse().reduce(function (carry, digit, index) { | |
if (from_range.indexOf(digit) === -1) throw new Error('Invalid digit `'+digit+'` for base '+from_base+'.'); | |
return carry += from_range.indexOf(digit) * (Math.pow(from_base, index)); | |
}, 0); | |
var new_value = ''; | |
while (dec_value > 0) { | |
new_value = to_range[dec_value % to_base] + new_value; | |
dec_value = (dec_value - (dec_value % to_base)) / to_base; | |
} | |
return new_value || '0'; | |
} |
Here is a bug:
convertBase("04ef57aa335b86bce90cd99144be26fa47645c36624eeb54ae153bc67861f9a7ad96e23e0d200348bd6a442ef96bd04a2c177272bd92fd739f01e0520fa8f0cae9", 16, 36)
returns "5kwmq5si5koww4ww0gcgw48cggsocowosk8c0g84ws8gscowckgs0osssogk4kgc40ggo8w8gko48c0k808wc4os88oc00gs4ow8"
But: convertBase('5kwmq5si5koww4ww0gcgw48cggsocowosk8c0g84ws8gscowckgs0osssogk4kgc40ggo8w8gko48c0k808wc4os88oc00gs4ow8', 36, 16)
returns "4ef57aa335b8700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Here is some range conditions
let convertBase = (value, from_base, to_base) => {
let range = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/".split("");
if (from_base < 2 || from_base > range.length)
throw new RangeError(`convertBase() from_base argument must be between 2 and ${range.length}`);
if (to_base < 2 || to_base > range.length)
throw new RangeError(`convertBase() to_base argument must be between 2 and ${range.length}`);
let from_range = range.slice(0, from_base);
let to_range = range.slice(0, to_base);
let dec_value = value.split("").reverse().reduce((carry, digit, index) => {
let fromIndex = from_range.indexOf(digit);
if (fromIndex === -1)
throw new Error(`Invalid digit ${digit} for base ${from_base}.`);
return carry + fromIndex * Math.pow(from_base, index);
}, 0);
let new_value = "";
while (dec_value > 0) {
new_value = to_range[dec_value % to_base] + new_value;
dec_value = (dec_value - dec_value % to_base) / to_base;
}
return new_value || "0";
};
Support of large integer using native BigInt, (see browser support)
let bigIntPow = function power(x, y) {// x**y
let ZERO = BigInt(0);
if (y === ZERO) return BigInt(1);
let TWO = BigInt(2);
let p2 = power(x, y / TWO);
if (y % TWO === ZERO) return p2 * p2;
return x * p2 * p2;
};
let convertBaseBigInt = (value, from_base, to_base) => {
let range = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/".split("");
if (from_base < 2 || from_base > range.length)
throw new RangeError(`convertBase() from_base argument must be between 2 and ${range.length}`);
if (to_base < 2 || to_base > range.length)
throw new RangeError(`convertBase() to_base argument must be between 2 and ${range.length}`);
let from_range = range.slice(0, from_base);
let to_range = range.slice(0, to_base);
let from_base_big = BigInt(from_base);
let to_base_big = BigInt(to_base);
let dec_value = value.split("").reverse().reduce((carry, digit, index) => {
let fromIndex = from_range.indexOf(digit);
if (fromIndex === -1)
throw new Error(`Invalid digit ${digit} for base ${from_base}.`);
return carry + BigInt(fromIndex) * bigIntPow(from_base_big, BigInt(index));
}, BigInt(0));
let new_value = "";
while (dec_value > 0) {
new_value = to_range[dec_value % to_base_big] + new_value;
dec_value = (dec_value - dec_value % to_base_big) / to_base_big;
}
return new_value || "0";
};
test
let s = "4ef57aa335b86bce90cd99144be26fa47645c36624eeb54ae153bc67861f9a7ad96e23e0d200348bd6a442ef96bd04a2c";
console.log(convertBaseBigInt(convertBaseBigInt(s, 16, 36), 36, 16) === s);// true
Bug
// Base 10 to Base 26, also get issue Base26 to Base10 with hight numbers ...
// my testcase, nothing to explain ...
{
expected: "DGSJENFCE",
operande: "equal",
data: { num: "897521678123", srcAlphabet: NUMERALS_10.join(""), dstAlphabet: ALPHABET_LATIN.join("") }
},
BUT HAVE "EHTKFOGDF"
"DGSJENFCE" expected because of this
and another website have the same result but with your algo
Note: typeNumAmbiToStr is only for merge number and string to string
function swapBaseRef(valueA: string, baseA: string, ToBaseB: string) {
if (baseA.length !== ToBaseB.length) { throw new RangeError("swapBaseRef: need baseA and ToBaseB lenght equal"); }
return valueA
.split("")
.map((e, i) => { return ToBaseB[baseA.indexOf(e)] })
.join("")
}
export function anyBaseToAnyBase(num: string | number, srcAlphabet: string, dstAlphabet: string) {
let fromBase = srcAlphabet.length,
toBase = dstAlphabet.length;
let from_range = LONGEST_BASE.slice(0, fromBase);
let to_range = LONGEST_BASE.slice(0, toBase).join("");
const number = swapBaseRef(typeNumAmbiToStr(num, srcAlphabet), srcAlphabet, from_range.join(""));
let dec_value = number.split("").reverse().reduce((carry, digit, index) => {
let fromIndex = from_range.indexOf(digit);
if (fromIndex === -1) { throw new Error(`Invalid digit ${digit} for base ${fromBase}.`); }
return carry + fromIndex * Math.pow(fromBase, index);
}, 0);
let new_value = "";
while (dec_value > 0) {
new_value = to_range[dec_value % toBase] + new_value;
dec_value = (dec_value - dec_value % toBase) / toBase;
}
return swapBaseRef(new_value, to_range, dstAlphabet) || dstAlphabet[0];
};
please fixed youre code @ryansmith94 it would be awesome,
it works with small numbers but not with high numbers maybe theyre an issue when divide and float number ...
I saw a package wich have the same issue ("and we go again") ...
Because of this, prefer to use toString() ... ๐
@kzar79 @Juraj-Masiar @crispy-cat @apanasara @joeshae @zakariamouhid @c0ncentus
I moved this code to https://github.com/ryansmith94/baseroo and created issue #1 today and fixed the bug with large numbers. Thanks to @zakariamouhid for the suggested fix, I utilised that and tweaked it to work with TypeScript. Apologies for my slow reply, seemed I had notifications turned off for replies until recently, so thanks to @c0ncentus for persisting with that latest comment which did come through ๐
Now supports floats ryasmi/baseroo#37
conversion has less precision