Search code examples
combinationslogarithm

How can I use logarithms to get the opposite of power?


I was never good at maths in school and I realized that I actually need the opposite of pow(base, exponent) functions which powers some number by some factor like 2 ^ 4 = 16

Searching for answers I found that logarithm log() should be the opposite of power. Now, I've found that to write e.g. "log 2 of 32" would in code look like log(32) / log(2)... but how do you translate this following problem into logarithm?

I'm going to write a quick C program to print index table where all alphabetical characters are going to be printed assigned to each index starting from 0 to 26 ^ DIGITS.

Assuming DIGITS are set to 1, table will only be of size 26 (the length of alphabet from A to Z) in format index[0] = A, index[1] = B, ... ... index[25] = Z. The count of DIGITS gives 26 ^ DIGITS combinations.

Now, I have this code already written:

#include <stdio.h>
#include <ctype.h>
#include <math.h>

unsigned int letterToIndex(char c);
char indexToLetter(unsigned int index);

int main(void)
{

    printf("Printing Index table:\n\n");

    const int DIGITS = 2;
    const int ALPHABSIZE = 26;

    int currentIdx = 0; // current index

    const int endIndex = pow(ALPHABSIZE, DIGITS);
    
    // this should be 
    //double bit5 = log(32) / log(2);
    //printf("log(32) / log(2) AKA bit^5 should be: %f", bit5);
        
    while (currentIdx < endIndex)
    {
        
        printf("index[%i] = ", currentIdx);
        
        /*for (int i = 0; i < DIGITS; ++i)
        {
            //float logarithm = log( (currentIdx / ALPHABSIZE) % ALPHABSIZE ) / log(DIGITS);
            float logarithm = log( currentIdx % ALPHABSIZE ) / log(DIGITS);

            printf("%c", indexToLetter( (int) logarithm ));
        }*/
        
        
        // letter 
        //unsigned int idxLetter = letterToIndex(i) * ALPHABSIZE + letterToIndex(i+1);
        
        ///////////////////////////////////////////////////////////////////////////////
        // I have an obvious pattern here vv
        
        // here I print only 2 digits hard-coded
        // prints the 1st digit
        printf("%c", indexToLetter( (currentIdx / ALPHABSIZE) % ALPHABSIZE ));
        // prints the 2nd digit
        printf("%c", indexToLetter( currentIdx % ALPHABSIZE ));
        
        // obvious pattern ^^
        //////////////////////////////////////////////////////////////////////////////
        
        printf("\n");
        currentIdx++;
    }

    
    // if DIGITS are only 1 sized:
    // index[0] = A
    // index[1] = B
    // index[2] = C
    // index[3] = D
    // index[4] = E
    // ... ... ...
    // index[25] = Z

    // DIGITS having size of 2:
    // index[0] = AA
    // index[25] = AZ
    // index[26] = BA   =   index[ 1 * 26 + 0  ] = index[26]
    // index[30] = BE   =   index[ 1 * 26 + 4 ] = index[30]
    // ... ... ...
    // index[107] = ED =    index[ 4 * 26 + 3 ] = index[107]
 
    return 0;
}

// maps the ASCII range from 'A' = 0 to 'Z' = 25
unsigned int letterToIndex(char c)
{
    return toupper(c) - 'A';
}

// get any letter from 0 to 25: from 'A' to 'Z'
char indexToLetter(unsigned int index)
{
    return toupper(index + 65);
}

I've commented out the for loop inside the main (inside the while block), and this time hardcoded to printf currentIdx's first digit and then its second digit at each iteration in the while loop.

But it strikes me like it's asking for a logarithm... How can I automate this in the for loop? Instead of having two printf lines, I'm pretty much convinced these two lines:

printf("%c", indexToLetter( (currentIdx / ALPHABSIZE) % ALPHABSIZE ));
printf("%c", indexToLetter( currentIdx % ALPHABSIZE ));

could be put into one line with the right (maybe logarithm?) solution. If it was DIGITS size 1, only the 2nd line would apply. DIGITS of size 3 requires opposite of power to 3. It's clearly power to DIGITS.

But what to make out of this pattern in a loop? Let's say const int DIGITS (that's currently set to 2) could be changed to be higher. How to make it dynamic so that it'll combine the alphabet for every digit?


Solution

  • You can start with pow(ALPHABSIZE, DIGITS - 1) and use integer division to get each place value/table index. On each loop you successively reduce by a factor of ALPHABSIZE down to 1. This lets you output left to right.

    Logarithms are not necessary to compute here. To compute an integer logarithm you could nevertheless just count the number of passes through a while/for loop in the same fashion.