CFLib.org – Common Function Library Project

baseMToBaseN(number, fromBase, toBase)

Last updated September 24, 2012

author

Adam Cameron

Version: 1 | Requires: CF10 | Library: MathLib

Description:
Converts a number from one arbitrary base to another arbitrary base. Is not restricted to bases that Java and CF natively support in their equivalent built-in functions. The internal maths are restricted to the bounds of java.math.BigInteger though.

Return Values:
Returns a string, which is the original number converted to the specified base

Example:

test.description    = "A fairly easy to visually-test example";
test.number            = 255;
test._baseFrom        = "dec";
test._baseTo        = "bin";
test._result        = baseMToBaseN(test.number, test._baseFrom, test._baseTo);
writeDump(test);

Parameters:

Name Description Required
number The number to convert. Yes
fromBase The base to convert from. Can either be one of BIN, DEC, HEX, BASE36, BASE62 or an 'alphabet' or characters that represent the digits. EG: OCTAL would be 01234567. Yes
toBase The base to convert to. Has same value rules as fromBase. Yes

Full UDF Source:

/**
 * Converts a number from one arbitrary base to another arbitrary base.
 * v1.0 by Adam Cameron
 * 
 * @param number      The number to convert. (Required)
 * @param fromBase      The base to convert from.  Can either be one of BIN, DEC, HEX, BASE36, BASE62 or an 'alphabet' or characters that represent the digits. EG: OCTAL would be 01234567. (Required)
 * @param toBase      The base to convert to. Has same value rules as fromBase. (Required)
 * @return Returns a string, which is the original number converted to the specified base 
 * @author Adam Cameron (adamcameroncoldfusion@gmail.com) 
 * @version 1, September 24, 2012 
 */
string function baseMToBaseN(required string number, required string fromBase, required string toBase){
    if (fromBase == toBase){    // ie: there's nothing to do
        return number;
    }
    
    // I use BigIntegers in this because CF loses precision or overflows pretty quickly
    var getDigitsForBase = function(base){// abstracting this out because it's verbose and I need to do it twice 
        var result = {};
        switch (base){
            case "BIN":        result.digits="01"; break;
            case "DEC":        result.digits="0123456789"; break;
            case "HEX":        result.digits="0123456789ABCDEF"; break;
            case "BASE36":    result.digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; break;
            case "BASE62":    result.digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; break;
            default:        result.digits=base; break;
        }
        result.base = createObject("java", "java.math.BigInteger").init(javaCast("String", len(result.digits)));
        return result;
    };

    var from            = getDigitsForBase(fromBase); 
    var to                = getDigitsForBase(toBase); 
    var srcDigits        = reverse(number);
    var digit            = "";
    var baseMultiplier    = createObject("java", "java.math.BigInteger").init("1");    // NB: BigInteger inits with a string, hence the quotes
    var digitMultiplied    = 0;
    var digitValue        = 0;
    var decValue        = createObject("java", "java.math.BigInteger").init("0");
    var result            = "";
    
    // the first step is converting the number to decimal. If it's already a decimal, we can skip this bit
    if (fromBase == "DEC"){
        decValue        = createObject("java", "java.math.BigInteger").init(javaCast("String", number));
    }else{
        while (len(srcDigits) > 0){    // the algorithm is basically go through each digit, and multiple it by increasing powers of the base we're converting to
            // get the next char and its value
            digit            = left(srcDigits, 1);
            digitValue        = createObject("java", "java.math.BigInteger").init(javaCast("String", find(digit, from.digits) - 1));

            // add it to the total
            digitMultiplied = baseMultiplier.multiply(digitValue);
            decValue        = decValue.add(digitMultiplied);

            // get ready for next iteration
            srcDigits        = removeChars(srcDigits, 1, 1);
            baseMultiplier = baseMultiplier.multiply(from.base);
        }
    }

    // convert from a decimal into the specified base: progressively note the remainder as we divide the number by the base
    while (decValue >= to.base){
        digitValue    = decValue.mod(to.base);
        digit        = mid(to.digits, digitValue+1, 1);
        result        = digit & result;
        decValue    = decValue.divide(to.base);
    }
    
    // and do the last digit, which is all that is left after the loop
    digit    = mid(to.digits, decValue+1, 1);
    result    = digit & result;
    
    return result;
}

Search CFLib.org


Latest Additions

Raymond Camden added
QueryDeleteRows
November 04, 2017

Leigh added
nullPad
May 11, 2016

Raymond Camden added
stripHTML
May 10, 2016

Kevin Cotton added
date2ExcelDate
May 05, 2016

Raymond Camden added
CapFirst
April 25, 2016

Created by Raymond Camden / Design by Justin Johnson