Search code examples
c++radixalphanumericnumber-systems

How to define a new number system in C++


Essentially what I'm attempting to do is create a base 62 number system in C++ (an alphanumeric number system -- one that includes a-z, A-Z, and 0-9). How would something like this be accomplished? I tried using a char array like this:

const char alphaNum[62] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', ' y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

however writing functions to use that array and try to count takes way too much code to be practical (for 0 to 61, sure, just select it from the array. The problem arises when you try to do multiple-digit numbers, i.e. 00). It would be much simpler to just say foobar++;. Does anyone have a way to define number systems, or at least a way for me to make it so that I don't have to write a case for every time it reaches Z?

EDIT: it should have been const char, dunno why VS decided it would be fun not to copy some of it.


Solution

  • Following may help: (http://ideone.com/y1gZDF) (You may change the internal representation to fit you need, as a BigNumber).

    class N62
    {
    public:
        explicit N62(const std::string& digits) : N62(digits.c_str(), digits.size()) {}
        N62(const char* digits, std::size_t len) : value(0u)
        {
            for (std::size_t i = 0; i != len; ++i) {
                auto pos = std::find(std::begin(base), std::end(base), digits[i]);
                if (pos == std::end(base)) {
                    throw std::runtime_error("incorrect digit");
                }
                value *= 62;
                value += pos - std::begin(base);
            }
        }
        N62(std::size_t value) : value(value) {}
        operator std::size_t () const { return value; }
        std::string str() const
        {
            if (value == 0u) {
                return "0";
            }
            std::string res;
            for (std::size_t n = value; n != 0; n /= 62) {
                res.push_back(base[n % 62]);
            }
            std::reverse(res.begin(), res.end());
            return res;
        }
    
    private:
        std::size_t value;
    private:
        static constexpr char base[] =
            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    };
    

    Additionally, you may add a user string literal as follow:

    N62 operator "" _n62 (const char *t, std::size_t len)
    {
        return N62(t, len);
    }
    

    And use it that way : "1Z"_n62 (which resolve in 123 in decimal).