views:

223

answers:

4

I have a method that converts an int to a base60 string (using 0-9, a-z, and A-Z chars), but can't work out how to convert it back again. Here is my method for converting base10 to base60:

public static function toBase60(value:Number):String 
{
    var targetBase:uint = 60;
    value = value.toString().split('.')[0];
    var digits:Array = new Array();
    while (value > 0) 
    {
        digits.push(baseChars[value % targetBase]);
        value = Math.floor(value / targetBase);
    }
    var myResult:String = digits.reverse().join('');
    return myResult;
}

Works well. But how do I get the base60 string back into a base10 int? I happen to be using ActionScript 3, but really, examples in any programming language, generic explanations or sudo code would be great.

+4  A: 
total = 0;
for each digit (front to back)
  total = total * 60 + digit
Tom Sirgedas
Shouldn't it be `total**60 * digit`, where `**` is exponentiation?
Adrian
no, it's good the way it is
fazo
@Adrian: Nope, for example, 93 [base 60] is 543 [base 10] (9*60+3). Also, 7000 [base 60] is 7*(60**3). My code gets this by multiplying 7 by 60 three times.
Tom Sirgedas
A: 

Assuming you have a function int digit60to10(char digit) that converts [0-9a-zA-Z] into the equivalent decimal value for a single digit, you can do this:

int decimalValue = 0;
foreach digit in digits (most to least significant):
  decimalValue *= 60;
  decimalValue += digit60to10(digit);
Drew Hall
+2  A: 

One way of doing this could be:

    public static function fromBase60(value:String):Number {
        var result:Number = 0;
        var targetBase:uint = 60;
        var digitValue:int = 0;
        for(var i:int = 0, j:int = value.length - 1; j >= 0; i++,j--) {
            digitValue = reverseMap[value.charAt(j)];
            result += Math.pow(targetBase,i) * digitValue; 
        }
        return result;
    }

Looks like you have an array that maps numbers (digits) to characters, so you could build a reverse map upfront and make the lookup easier. With some code like this:

    // add this code to your class
    private static var reverseMap:Object = {};

    private static function buildReverseMap():void {
        var len:int = baseChars.length;
        for(var i:int = 0; i < len; i++) {
            reverseMap[baseChars[i]] = i;
        }
    }

    // initialize the reverse map
    {
        buildReverseMap();
    }

Edit

Alternative implementation, based on algorithm posted by Tom Sirgedas. This avoids calling Math.pow, though I doubt you'll note much difference in practice (performance-wise):

    public static function fromBase60(value:String):Number {
        var result:Number = 0;
        var targetBase:uint = 60;
        var digitValue:int = 0;
        var len:int = value.length;
        for(var i:int = 0; i < len; i++) {
            digitValue = reverseMap[value.charAt(i)];
            result = result * targetBase + digitValue; 
        }
        return result;
    }
Juan Pablo Califano
A: 

This could give you some problems. But that is not Base 60, it's base 62

Edit Since the above is not a viewed as a valid answer, here is how I converted base 62 <=> 10 in PHP, though there are many methods to do so. http://ken-soft.com/?p=544

I also, explained why I posted that as an answer in the below comment (though I agree it was way too brief) :) sorry.
Edit why is this getting voted down? What I said is true!

KennyCason
This is not an answer!
TandemAdam
Well, it may have not been a complete answer, but I felt it was relevant to solving your problem to point out that it if you are using a Base 62 Character set and trying to convert it using Base 60, then your results will be wrong.
KennyCason
Except there's nothing wrong about it, as long as the decoder and encoder understand that the base is 60. There are simply two letters unused.
hobbs
right, That I agree 100%, (unless you use a base that is higher than the alphabet, which he's not). That's why on the link I posted you will notice that The algorithms never change, only the character set. I was honestly just trying to help him debug the problem, because if you are using a base62 alphabet but converting using base60, that would definitely result in unexpected behavior.
KennyCason