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;
}
blog comments powered by Disqus

Search CFLib.org


Latest Additions

Kevin Cotton added
date2ExcelDate
May 5, 2016

Raymond Camden added
CapFirst
April 25, 2016

Chris Wigginton added
loremIpsum
January 18, 2016

Gary Stanton added
calculateArrival...
November 19, 2015

Sebastiaan Naafs - van Dijk added
getDaysInQuarter
November 13, 2015

Created by Raymond Camden / Design by Justin Johnson