Skip to content

Instantly share code, notes, and snippets.

@ryasmi
Last active August 11, 2023 10:07
Show Gist options
  • Save ryasmi/91d7fd30710264affeb9 to your computer and use it in GitHub Desktop.
Save ryasmi/91d7fd30710264affeb9 to your computer and use it in GitHub Desktop.
Moved to https://github.com/ryasmi/baseroo - Converts a number represented as a string from one base to another (up to 64).
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';
}
@cyoce
Copy link

cyoce commented Feb 5, 2016

It would be great to add support for floats. E.g. convertBase("1.2", 10, 64)

@g2384
Copy link

g2384 commented Apr 21, 2017

@cyoce there are many ways to represent float numbers, so we don't know which float representation do you want. When we are talking about base, we usually mean integers.

@kzar79
Copy link

kzar79 commented Jun 12, 2018

This doesn't work for numbers > 2^53

@Juraj-Masiar
Copy link

Any chance adding support for a very big numbers?

@crispy-cat
Copy link

THANK YOU! This works great for my converter tool!

@crispy-cat
Copy link

Just a little issue: Numbers over 2^64/2 will get a bit weird
image
image

@apanasara
Copy link

conversion has less precision

var x = "89999999179999999";  // String written inside quotes
x=convertBase(x,10,36);
document.getElementById("base36").innerHTML = x;
document.getElementById("base10").innerHTML = convertBase(x,36,10);

/*OUTPUT
base36 : om6c4ucnke8
base10 : 89999999180000000
*/

@joeshae
Copy link

joeshae commented Sep 8, 2019

Here is a bug:
convertBase("04ef57aa335b86bce90cd99144be26fa47645c36624eeb54ae153bc67861f9a7ad96e23e0d200348bd6a442ef96bd04a2c177272bd92fd739f01e0520fa8f0cae9", 16, 36)
returns "5kwmq5si5koww4ww0gcgw48cggsocowosk8c0g84ws8gscowckgs0osssogk4kgc40ggo8w8gko48c0k808wc4os88oc00gs4ow8"

But: convertBase('5kwmq5si5koww4ww0gcgw48cggsocowosk8c0g84ws8gscowckgs0osssogk4kgc40ggo8w8gko48c0k808wc4os88oc00gs4ow8', 36, 16)
returns "4ef57aa335b8700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

@zakariamouhid
Copy link

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

@c0ncentus
Copy link

c0ncentus commented Jan 4, 2023

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
image
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() ... 👎

@ryasmi
Copy link
Author

ryasmi commented Jan 5, 2023

@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 👍

@ryasmi
Copy link
Author

ryasmi commented Jan 28, 2023

Now supports floats ryasmi/baseroo#37

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment