1

標準のCで次のことを行う方法を理解する必要があります。たとえばn桁の16進数を表す文字列が与えられていると仮定します。これを、同じ数値を10進数で表す文字列に変換します。文字列の桁数は任意です。少なくとも推測しやすいのは、10進文字列には2n文字未満が必要であるということです。

マシンが処理できる数値のサイズ制限に達すると、文字列の長さはまったく無関係になるため、100桁の16進数は、1000桁の数値と同じように簡単/困難に変換できます。つまり、同じアルゴリズムを使用する必要があります。チャンクで動作する必要があるため、両方で動作します。

ここで誰かがこれについて考えましたか?本当に厄介なのは、2の大きな累乗が1桁目までゼロ以外の桁を持っているため、16進シーケンスの要素が10進数の最後の桁に影響を与える可能性があることです...

誰かが文字列を数値に変換したい、または数値を文字列に変換したいという質問しか見つかりませんでした。誰かがなぜ私がこれを必要とするのか疑問に思ったら。私は任意精度の数値で遊んでいますが、数値を格納するための最も経済的な形式は基数256であるため、この形式(または同等の16進数)で指定された数値を印刷する必要があります。

編集:それで私は変換関数を実装しました、そして他の誰かがそれを必要とするかもしれないならここでそれを共有します。これは非常に迅速で汚いものであり、より良い実装はもちろん、構造体の数字バッファを動的に割り当てられるものに置き換えることから始まります。すべての演算は「add」関数で行われるため、加算がオーバーフローした場合に、このバッファーをより大きなものに再割り当てするのは簡単です。16進数は、2桁以下の10進数に変換されるため、出力バッファサイズの割り当ては常に簡単です。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLEN 1000


struct number {
    unsigned char digits[MAXLEN];
    unsigned int num_digits;
};

int add(struct number *, struct number *, struct number *);
int mult(struct number *, struct number *, struct number *);
int power(struct number *, unsigned int, struct number *);
void print_number(struct number *, char *);
void dec(struct number *);

void hex2dec(char *hex, char *outbuf)
{
    int n;
    char *s;
    struct number decrep;
    struct number twopow;
    struct number digit;

    decrep.num_digits = 0;

    n = strlen(hex);
    s = hex;

    while(--n > -1) {
        /* weight of digit */
        twopow.num_digits = 2;
        twopow.digits[0] = 6;
        twopow.digits[1] = 1;
        power(&twopow, n, &twopow);

        /* Extract digit */
        if(*s <= '9' && *s >= '0') {
            digit.digits[0] = *s - '0';
            digit.num_digits = 1;
        } else if(*s <= 'f' && *s >= 'a') {
            digit.digits[0] = *s - 'a';
            digit.digits[1] = 1;
            digit.num_digits = 2;
        } else if(*s <= 'F' && *s >= 'A') {
            digit.digits[0] = *s - 'A';
            digit.digits[1] = 1;
            digit.num_digits = 2;
        }

        s++;

        mult(&digit, &twopow, &digit);
        add(&decrep, &digit, &decrep);
    }

    /* Convert decimal number to a string */
    if(decrep.num_digits == 0) {
        *outbuf = '0';
        *(++outbuf) = '\0';
        return;
    }

    for(n = decrep.num_digits-1; n >= 0; n--) {
        *(outbuf++) = '0' + decrep.digits[n];
    }

    *outbuf = '\0';
}

int main(void)
{
    char buf[1000];

    hex2dec("FFEa4334234FABCD", buf);

    printf("%s", buf);
    return 0;
}

void copy_number(struct number *dst, struct number *src)
{
    int i;

    for(i = 0; i < src->num_digits; i++) dst->digits[i] = src->digits[i];

    dst->num_digits = src->num_digits;
}

int power(struct number *a, unsigned int n, struct number *b)
{
    struct number atmp;

    /* Are we exponentiating by 0? */
    if(n == 0) {
        b->num_digits = 1;
        b->digits[0] = 1;
        return 0;
    }

    copy_number(&atmp, a);

    while(--n > 0) {
        mult(&atmp, a, &atmp);
    }

    copy_number(b, &atmp);
    return 0;
}

int mult(struct number *a, struct number *b, struct number *c)
{
    struct number btmp;
    struct number ctmp;
    struct number *t;

    /* Are we multiplying by 0? */
    if(a->num_digits == 0 || b->num_digits == 0) {
        c->num_digits = 0;
        return 0;
    }

    if(a->num_digits < b->num_digits) {
        t = a;
        a = b;
        b = t;
    }

    copy_number(&btmp, b);
    copy_number(&ctmp, a);

    while(1) {
        /* Are we multiplying by 1? */
        if(btmp.num_digits == 1 && btmp.digits[0] == 1) {
            break;
        }

        add(&ctmp, a, &ctmp);
        dec(&btmp);
    }

    copy_number(c, &ctmp);

    return 0;
}

int add(struct number *a, struct number *b, struct number *c)
{
    int i, j;
    int carry;

    struct number *t;

    if(a->num_digits < b->num_digits) {
        t = a;
        a = b;
        b = t;
    }

    for(i = 0, carry = 0; i < a->num_digits; i++) {

        if(i >= b->num_digits) j = a->digits[i]+carry;
        else j = a->digits[i]+b->digits[i]+carry;

        if(j > 9) {
            j -= 10;
            carry = 1;
        } else {
            carry = 0;
        }

        c->digits[i]=j;
    }

    /* Did we overflow? */
    if(carry > 0 && i == MAXLEN) return -1;

    /* Carry over from last addition? */
    if(carry > 0) {
        c->digits[i] = carry;
        c->num_digits = a->num_digits+1;
    } else {
        c->num_digits = a->num_digits;
    }

    return 0;
}

void print_number(struct number *a, char *buf)
{
    int i;

    if(a->num_digits == 0) {
        printf("0");
        return;
    }

    for(i = a->num_digits-1; i >= 0; i--) {
        *(buf++) = '0' + a->digits[i];
    }

    *buf = '\0';
}

void dec(struct number *a)
{
    int i;

    for(i = 0; i < a->num_digits; i++) {
        if(a->digits[i] > 0) {
            a->digits[i]--;
            break;
        }

        a->digits[i] = 9;
    }

    /* Did number of digits get lower */
    if(i == a->num_digits -1 && a->digits[i] == 0) {
        for(i = a->num_digits - 1; i >= 0; i--) {
            if(a->digits[i] != 0) {
                a->num_digits = i + 1;
                break;
            }
        }
    }
}
4

1 に答える 1