Skip to content

Instantly share code, notes, and snippets.

@adamcameron
Created September 24, 2012 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamcameron/3776135 to your computer and use it in GitHub Desktop.
Save adamcameron/3776135 to your computer and use it in GitHub Desktop.
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.
/**
@hint 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.
@number The number to convert.
@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.
@toBase The base to convert to. Has same value rules as fromBase.
*/
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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment