4

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.

4

3 回答 3

8

您需要将外部(对用户)表示和内部表示分开。

内部表示
在计算机内部,您应该使用最有效的表示。这可以是十六进制、二进制或十进制;或者不用担心。

向用户展示时,您应该使用外部展示。

外部表示
您的字符数组表示您的数字系统的数字。(也应该是const。)您需要将数字与内部表示隔离开来。例如,在基数为 16 的情况下,我们将数字除以 16 以将数字右移并使用除法得到余数。余数是数字值。使用余数从数组中查找数字表示。

在较小的数字基数上尝试您的算法,例如 17 或 18。扩展到基数 62 应该是更改 a#define或的问题const integer

编辑1:困难的方法
一个更困难的方法是为数字系统的每个数字使用一个字节。字节、八位字节或无符号字符的范围为 0 到 255,因此应容纳以 62 为基数的数字。

使用 astd::vector<unsigned char>代表您的号码。您必须决定最高有效数字是在向量的前面还是在末尾。

要增加一个数字:

  add 1 to digit.
  if digit value > 62
  {
     set digit to zero.
     Load digit with next greater column value (i.e. vector[position + 1];
     Repeat at top of algorithm
  }

这是标准算法,无论基数如何(10、8、16 等)。
十进制加法、减法、乘法和除法的基本规则仍然适用。(暗示)。

这是Big Number库中使用的一种技术。

于 2014-06-14T20:56:17.697 回答
4

以下可能会有所帮助:(http://ideone.com/y1gZDF)(您可以更改内部表示以适合您的需要,作为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";
};

此外,您可以添加用户字符串文字,如下所示:

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

并以这种方式使用它:(以十进制"1Z"_n62解析123)。

于 2014-06-14T21:53:31.490 回答
1

数字系统只是数字的表示。数字不介意我们如何写它们。所以,我们的问题是:

如何使用base62在程序文本中声明数字?

您应该声明如何标记 base62 数字。“0x”和“$”前缀是为base16保留的,“0”前缀是为八进制保留的,“%”是二进制的前缀,“*”有几个原因可能是你的前缀,例如:~Uu3n

然后,您应该编写一个预处理器,它将您的 base62 数字转换为十进制(或您想要的十六进制)格式。

如何以base62输出数字?

这更难。您应该将所有数字输出转换为 base62。所以

 printf("%d in base62 is %D \n",value,value);

应该转换为

 printf("%d in base62 is %s \n",value,tob64(value));

不太优雅。


也许包装类应该更好(如Java 中的Integer)。

于 2014-06-14T21:09:35.300 回答