4

基本的に私がやろうとしているのは、C++ で base 62 数値システム (az、AZ、および 0-9 を含む英数字の数値システム) を作成することです。このようなことはどのように達成されるでしょうか?次のようなchar配列を使用してみました:

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' };

ただし、その配列を使用してカウントしようとする関数を作成するには、コードが多すぎて実用的ではありません (0 から 61 の場合は、配列から選択するだけです。複数桁の数値、つまり 00 を実行しようとすると問題が発生します)。 . と言う方がはるかに簡単foobar++;です。数体系を定義する方法、または少なくとも Z に到達するたびにケースを作成する必要がないようにする方法を誰かが持っていますか?

編集: const char である必要がありましたが、VS がその一部をコピーしない方が楽しいと判断した理由はわかりません。

4

3 に答える 3

8

外部 (ユーザーに対する) 表現と内部表現を分離する必要があります。

内部表現
コンピュータの内部では、最も効率的な表現を使用する必要があります。これは、16 進数、2 進数、または 10 進数です。または心配しないでください。

ユーザーに提示する場合は、外部表現を使用する必要があります。

外部表現
文字配列は、数体系の数字を表します。(これも である必要がありますconst。) 内部表現から数字を分離する必要があります。たとえば、基数 16 では、数値を 16 で割って数値を右にシフトし、モジュロ除算を使用して余りを取得します。残りは数字の値です。残りを使用して、配列から数字表現を検索します。

17 や 18 など、より小さな基数でアルゴリズムを試してください。基数 62 に拡張するには、#defineまたはを変更する必要がありconst integerます。

編集 1: 難しい方法
より難しい方法は、数体系の各桁に 1 バイトを使用することです。バイト、オクテット、または unsigned char の範囲は 0 ~ 255 であるため、base 62 の数字に対応する必要があります。

番号を表すには a を使用しstd::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);
}

そして、そのように使用してください:(これは10進数"1Z"_n62で解決されます)。123

于 2014-06-14T21:53:31.490 に答える
1

数体系は数の表現にすぎません。数字は、私たちがどのように書いても構いません。したがって、私たちの問題は次のとおりです。

プログラムテキストでbase62を使用して数値を宣言する方法は?

base62 番号をマークする方法を宣言する必要があります。"0x" および "$" プレフィックスは base16 用に予約されています。"0" プレフィックスは 8 進数用に予約されています。"%" プレフィックスはバイナリ用に予約されています。"*" はいくつかの理由で使用されています。

次に、base62 数値を 10 進数 (または必要に応じて 16 進数) 形式に変換するプリプロセッサを作成する必要があります。

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 に答える