Infinibase Icon

Infinibase

Release Date: 2012

Language Used:

Objective-C

Software Used:

Xcode

Platforms:

iOS

About:

Infinibase was my second iOS app, one that revolved around converting numbers between bases. It started as a simple app to convert between the popular bases (2, 8, 10 and 16), but was later upgraded to handle bases 2 through 36. Inspiration for this app comes from an intro to programming class, where an assignment tasked us with coding a command line binary to decimal converter.

This app uses custom drawing code to generate a keyboard tailored to the currently selected base system. This is to prevent inappropriate input as well as to enhance the user experience.

Infinibase's name comes from the fact that it is capable of converting theoretically limitless numbers. This is thanks to its usage of the GMP Multi-Precision Arithmetic Library, which can create numbers whose precision is only limited by the memory of the device the app is running on.

Code Samples

Anything to decimal conversion

The first part of the base conversion is to convert whatever the input is to base-10. Base-10 can be easily converted to any other base, so it is the best place to start.
// converts any base to decimal
// start with the first number on the right of the input
// multiply that by the base of the number to the power of the numbers slot (first number is slot 0)
// repeat for each number in the input, add the results together
// example: 2132 base-4 to base-10
// (2 * 4^3) + (1 * 4^2) + (3 * 4^1) + (2 * 4^0)
// 128 + 16 + 12 + 2 = 158
// 2132 base-4 = 158 base-10
- (NSString *)convertNonDecimalNumberToDecimal:(NSString *)input fromBase:(int)oldBase {
    NSString *inputString = input;      // copy the input into input string, so we can remove the first character each loop
    NSString *finalString = @"";        // this will be the string version of finalNumber
    NSString *currentNumber;            // current digit that the loop will be working on
    
    mpz_t currentPower;         // current power we use on the current number - starts with 0
    mpz_t finalNumber;          // final number - incremented each loop
    mpz_init(currentPower);
    mpz_init(finalNumber);
    
    // we use 0 and 1 a lot, no need to keep creating them in the loop
    mpz_t zero;
    mpz_t one;
    mpz_init(zero);
    mpz_init(one);
    mpz_set_si(zero, 0);
    mpz_set_si(one, 1);
    
    mpz_t currentNumberInt;
    mpz_t x;
    mpz_init(currentNumberInt);
    mpz_init(x);
    
    // the base we are converting from
    mpz_t oldBaseGMP;
    mpz_init_set_si(oldBaseGMP, oldBase);
    
    mpz_t oldBaseRootCurrentPower;
    mpz_init(oldBaseRootCurrentPower);
    
    // run the loop while inputString still has digits left
    do {
        // get the first number on the right of the input string (2 (string))
        currentNumber = [inputString substringFromIndex:[inputString length]-1];
        
        // assign the current number to currentNumberInt (2 (number))
        mpz_set_str(currentNumberInt, [currentNumber UTF8String], oldBase);
        
        // set oldBaseRootCurrentPower to oldBaseGMP ^ currentPower (4 ^ 0)
        [self GMPPowWithResult:oldBaseRootCurrentPower withBase:oldBaseGMP power:currentPower];
        
        // multiply the current digit by the result of oldBaseRootCurrentPower (2 * 4 ^ 0)
        mpz_mul(x, currentNumberInt, oldBaseRootCurrentPower);
        
        // set finalNumber to finalNumber + x
        mpz_add(finalNumber, finalNumber, x);
        
        // set currentPower to currentPower + 1
        mpz_add(currentPower, currentPower, one);
        
        // reset oldBaseRootCurrentPower to 0
        mpz_set_si(oldBaseRootCurrentPower, 0);
        
        // remove the first digit from inputString
        inputString = [inputString substringToIndex:[inputString length]-1];
    } while ([inputString length] != 0);
    
    // get a base-10 version of the fianlNumber as a char array, convert that to an NSString
    char *finalChar = mpz_get_str(NULL, 10, finalNumber);
    finalString = [NSString stringWithFormat:@"%s", finalChar];
    
    // memory cleanup
    mpz_clears(currentPower, finalNumber, zero, one, currentNumberInt, x, oldBaseGMP, oldBaseRootCurrentPower, NULL);
    
    return finalString;
}

Decimal to anything conversion

The second part of the base conversion is to convert the number in base-10 form to bases 2 through 36 (excluding base-10).
// converts deciaml to any base
// first find the largest number to the power of the input base that will fit in the new number
// then start dividing in a similar fashion as any number to decimal: start with the largest base, decrement each time
// append the result to the end of the final number
// use the remainder as the divisor for the next run
// example: 223 base-10 to base-5
// largest base that will fit in 223: 3 (5^3 = 125, 5^4 = 625 which is too big)
// 223 / 5^3 = 1, remainder 98
// 98 / 5^2 = 3, remainder 23
// 23 / 5^1 = 4, remainder 3
// 3 / 5^0 = 3, remainder 0
// 223 base-10 = 1343 base-5
- (NSString *)convertNumberFromDecimal:(NSString *)input toBase:(int)newBase {
    // we use 0 and 1 a lot, no need to keep creating them in the loop
    mpz_t zero;
    mpz_t one;
    mpz_init(zero);
    mpz_init(one);
    mpz_set_si(zero, 0);
    mpz_set_si(one, 1);
    
    // used in the loop
    mpz_t inputNumber;
    mpz_t baseRootCurrentPower;
    mpz_t divided;
    mpz_t currentPower;
    NSMutableString *finalString = [NSMutableString stringWithString:@""];
    BOOL isAtCorrectPower = FALSE;  // used for determining our initial power
    
    // init some vars
    mpz_inits(inputNumber, baseRootCurrentPower, divided, currentPower, NULL);
    
    // set inputNumber to a number version of the input string, in base 10
    mpz_set_str(inputNumber, [input UTF8String], 10);
    
    // set base equal to newBase
    mpz_t base;
    mpz_init(base);
    mpz_set_si(base, newBase);
    
    // used in the loop, declaring once here
    mpz_t inputNumberMinusBaseRootCurrentPower;
    mpz_init(inputNumberMinusBaseRootCurrentPower);
    
    // if the input is 0, no need to do any big conversions
    if ([input isEqualToString:@"0"]) {
        finalString = [NSMutableString stringWithString:@"0"];
    } else {
        
        // we need to find the power of the new base that will still fit inside the input number
        do {
            // store base^currentPower in baseRootCurrentPower
            [self GMPPowWithResult:baseRootCurrentPower withBase:base power:currentPower];
            
            // set inputNumberMinuxBaseRootCurrentPower to 0
            mpz_set_si(inputNumberMinusBaseRootCurrentPower, 0);
            
            // first, set inputNumberMinusBaseRootCurrentPower to inputNumber, then do the actual subtraction
            mpz_set(inputNumberMinusBaseRootCurrentPower, inputNumber);
            mpz_sub(inputNumberMinusBaseRootCurrentPower, inputNumberMinusBaseRootCurrentPower, baseRootCurrentPower);
            
            // compares inputNumberMinusBaseRootCurrentPower and 0.
            // if it is greater than 0, a positive number is returned
            // if it is equal to 0, 0 is returned
            // if it is less than 0, a negative number is returned
            // so, if inputNumberMinusBaseRootCurrentPower >= 0, increment currentPower by 1
            // otherwise we've found a power that will result in a number too great for the input number,
            // so decrement currentPower by 1 and set the bool to true to get out of the loop
            if (mpz_cmp(inputNumberMinusBaseRootCurrentPower, zero) >= 0) {
                mpz_add(currentPower, currentPower, one);
            } else {
                mpz_sub(currentPower, currentPower, one);
                isAtCorrectPower = TRUE;
            }
            
            // reset baseRootCurrentPower back to 0
            mpz_set_si(baseRootCurrentPower, 0);
        } while (isAtCorrectPower == FALSE);
        
        // clamp currentPower to 0
        if (mpz_cmp(currentPower, zero) < 0) {
            mpz_set(currentPower, zero);
        }
        
        // perform this loop while currentPower is >= 0
        do {
            // store base^currentPower in baseRootCurrentPower
            [self GMPPowWithResult:baseRootCurrentPower withBase:base power:currentPower];
            
            // store inputNumber / baseRootCurrentPower in divided. this is the digit we will append to the final string
            mpz_div(divided, inputNumber, baseRootCurrentPower);
            
            // store inputNumber % baseRootCurrentPower in inputNumber. this is the number we will divide by on the next loop run
            mpz_mod(inputNumber, inputNumber, baseRootCurrentPower);
            
            // append the divided string to the end of the final string. run it through a special function to
            // convert it to a letter if necessary (eg 11 = A)
            [finalString appendString:[NSString stringWithFormat:@"%@", [self determineNumberOrLetter:mpz_get_ui(divided)]]];
            
            // decrement currentPower by 1
            mpz_sub(currentPower, currentPower, one);
        } while (mpz_cmp(currentPower, zero) >= 0);
    }
    
    // memory cleanup
    mpz_clears(zero, one, inputNumber, baseRootCurrentPower, divided, currentPower, base, inputNumberMinusBaseRootCurrentPower, NULL);
    
    return finalString;
}