Skip to content

Instantly share code, notes, and snippets.

@ryasmi
Last active August 11, 2023 10:07
Show Gist options
  • Select an option

  • Save ryasmi/91d7fd30710264affeb9 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

cyoce commented Feb 5, 2016

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

@g2384
Copy link
Copy Markdown

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
Copy Markdown

kzar79 commented Jun 12, 2018

This doesn't work for numbers > 2^53

@Juraj-Masiar
Copy link
Copy Markdown

Any chance adding support for a very big numbers?

Copy link
Copy Markdown

ghost commented Mar 9, 2019

THANK YOU! This works great for my converter tool!

Copy link
Copy Markdown

ghost commented Mar 10, 2019

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

@apanasara
Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown
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
Copy Markdown
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