Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Base Conversion Problem

I'm trying to convert an integer to a string right now, and I'm having a problem.

I've gotten the code written and working for the most part, but it has a small flaw when carrying to the next place. It's hard to describe, so I'll give you an example. Using base 26 with a character set consisting of the lowercase alphabet:

0 = "a"
1 = "b"
2 = "c"

...

25 = "z"
26 = "ba" (This should equal "aa")

It seems to skip the character at the zero place in the character set in certain situations.

The thing that's confusing me is I see nothing wrong with my code. I've been working on this for too long now, and I still can't figure it out.

char* charset = (char*)"abcdefghijklmnopqrstuvwxyz";
int charsetLength = strlen(charset);

unsigned long long num = 5678; // Some random number, it doesn't matter
std::string key

do
{
    unsigned int remainder = (num % charsetLength);
    num /= charsetLength;

    key.insert(key.begin(), charset[remainder]);

} while(num);

I have a feeling the function is tripping up over the modulo returning a zero, but I've been working on this so long, I can't figure out how it's happening. Any suggestions are welcome.

EDIT: The fact that the generated string is little endian is irrelevant for my application.

like image 652
jakogut Avatar asked Jul 02 '26 10:07

jakogut


2 Answers

If I understand correctly what you want (the numbering used by excel for columns, A, B, .. Z, AA, AB, ...) this is a based notation able to represent numbers starting from 1. The 26 digits have values 1, 2, ... 26 and the base is 26. So A has value 1, Z value 26, AA value 27... Computing this representation is very similar to the normal reprentation you just need to adjust for the offset of 1 instead of 0.

#include <string>
#include <iostream>
#include <climits>

std::string base26(unsigned long v)
{
    char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    size_t const base = sizeof(digits) - 1;
    char result[sizeof(unsigned long)*CHAR_BIT + 1];
    char* current = result + sizeof(result);
    *--current = '\0';

    while (v != 0) {
        v--;
        *--current = digits[v % base];
        v /= base;
    }
    return current;
}

// for testing
#include <cstdlib>

int main(int argc, char* argv[])
{
    for (int i = 1; i < argc; ++i) {
        unsigned long value = std::strtol(argv[i], 0, 0);
        std::cout << value << " = " << base26(value) << '\n';
    }
    return 0;
}

Running with 1 2 26 27 52 53 676 677 702 703 gives

1 = A
2 = B
26 = Z
27 = AA
52 = AZ
53 = BA
676 = YZ
677 = ZA
702 = ZZ
703 = AAA
like image 75
AProgrammer Avatar answered Jul 04 '26 23:07

AProgrammer


Your problem is that 'a' == 0.

In other words, 'aa' is not the answer, because that is really 00. 'ba' is the correct answer because b = '1', so that makes it 10 in base 26, which is 26 in decimal.

Your code is correct, you just seem to be misunderstanding it.

like image 23
Dan McGrath Avatar answered Jul 05 '26 01:07

Dan McGrath



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!