Мне нужно выяснить способ сделать следующее в стандартном C. Предположим, нам дана строка, представляющая шестнадцатеричное число с n разрядами. Мы хотим преобразовать это в строку, представляющую одно и то же число в десятичной форме. Строки могут иметь произвольное количество цифр. Что, по крайней мере, легко вывести, так это то, что десятичной строке требуется < = 2n букв.Преобразование длинной шестнадцатеричной строки в десятичную строку
Как только мы достигнем предела размера для чисел, которые машина может обрабатывать, длина строки становится совершенно неуместной, поэтому шестнадцатеричное число со 100 цифрами должно быть таким же простым и трудно конвертируемым, как одно с 1000 цифрами, т.е. тот же алгоритм должен работать на обоих, поскольку он должен работать в кусках.
Неужели кто-нибудь подумал об этом? Что действительно раздражает, так это то, что большие полномочия 2 имеют отличные от нуля цифры до первого порядка, поэтому любой элемент в шестнадцатеричной последовательности может влиять на последнюю цифру в десятичной ...
Я мог только найти вопросы, где кто-то хотел преобразовать строку к числу или числу к строке в некоторой базе. Если кто-то задается вопросом, зачем мне это нужно. Я играю с произвольными точками точности, а самый экономичный формат для хранения чисел в базе - 256, поэтому мне нужно напечатать числа, указанные в этой форме (или эквивалентно любой шестнадцатеричной).
EDIT: Итак, я внедрил функцию преобразования, и я поделюсь ею здесь, если кому-нибудь еще понадобится. Это было очень быстро грязно, и, конечно, лучше реализовать, заменив буфера цифр в структуре тем, что получает динамическое выделение. Так как вся арифметика происходит в функции «добавить», тогда было бы легко перераспределить этот буфер на нечто большее, если произойдет переполнение. Размер выходного буфера всегда прост для назначения, поскольку любое шестнадцатеричное число преобразуется в десятичное число с меньшим или равным удвоению цифр.
#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;
}
}
}
}
звучит так, как будто вам нужно google для 'c больших целых реализаций' –
Я согласен с @Colin. Проблема здесь в том, что вам нужно умножить цифру n (где единицы - цифра 0) на 16^n, чтобы получить десятичный эквивалент. Так как ваше n может быть большим (100 или 1000, из вашего поста), вы должны иметь возможность делать экспоненциальность очень больших чисел, что потребует большой целочисленной реализации. –
Хорошо, это было не так противно, как я думал. Поскольку вам нужно только взять полномочия с базой менее 16, мы все равно можем выполнить наивный алгоритм возведения в степень без необходимости выполнять деление на 2. – pki