LINUX.ORG.RU

Преобразовать массив чисел char в hex


0

1

Добрый день!
стоит следующая задача:
char *digits = «3224833640520308023»
как этот массив преобразовать в hex?
в результате должно получиться 2cc0e91c32f15537.
Ограничения: целевая платформа не поддерживает 64 битные числа.


Ответ на: комментарий от AIv

Наш вариант как раз все число в двоичную систему и переводит, гляньте внимательней. Отображение это уже дело вкуса.

Этот вариант работает только для чисел размером до (ULONG_MAX)^2. А, например, если мы захотим перевести в шестнадцатиричную систему число 3224833640520308023029478618762304098234786556432872378623459872345, что делать?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

> что делать?

воспользоваться функцией mpz_get_str из библиотеки gmp

aho
()
Ответ на: комментарий от Eddy_Em

С чего Вы взяли??? Задаем buf_sz нужного размера (шоб влезло), если хотите можете буфера выделять в куче, тогда ограничение будет - что б в влезло память два таких числа в двоичном представлении (десятичные цифирки можно тащщить с диска;-)))).

./a.out 3224833640520308023029478618762304098234786556432872378623459872345

1e9f22e6befe94f187065e0669d357ac428394e136afc01747384e59

AIv ★★★★★
()

Всем участникам обсуждения большое спасибо за оказанную помощь!

mguest
() автор топика
Ответ на: комментарий от Eddy_Em

Э... итоговое число хранится в виде кусочков, каждый кусочек это unsigned char (можно было б взять unsigned int но у ТС ограничение не более 32 бит). Исходное число переводим в довичное - каждую цифирку умножаем на 10 нужное число раз и прибавляем к общем рез-тату. Рез-тат выводим на печать в 16ти ричной форме.

По сранениию с традицонным сдвиг-с-коррекцией алгоритм имеет кубическую сложность, но поскольку оперирует большими кусками должен быть существенно быстрее (для чисел разумного размера). КРоме того, если так важна производительность алгоритм прекрасно параллелится скажем на GPU;-))))))))

AIv ★★★★★
()
Ответ на: комментарий от Eddy_Em

> Класс, а для строки произвольной длины?

Для строки произвольной длины так красиво не выйдет. Если нужно не 64 бита, а 96, то в код arsi придется добавить переменные 'c' и 'z'. Если не 96, а 128, то еще переменные 'd' и 'z2'. И так далее :) Закончим тем, что вместо переменных будем держать массивы, а код обзаведется новыми циклами. Получится почти как у AIv, только сложность будет квадратичная, а не кубическая.

Manhunt ★★★★★
()
Ответ на: комментарий от Eddy_Em

> Класс, а для строки произвольной длины?

для строки произвольной длины будет уже другой алгоритм. а этот — всего лишь реализация на сях классического способа работы с большими числами на ассемблере, и для х86 ассемблерный код выглядит намного красивее и понятнее.

не оптимальный вариант такого способа для произвольной длины (почти не тестил, могут быть косяки):

#include <stdio.h>
#include <memory.h>

void add_chr(char *big, char n /* 0..15 */, size_t len) {
        for (*big += n; *big > 15 && --len; *big &= 15, ++*++big);
        *big &= 15;
}

void add_big(char *a, const char *b, size_t len) {
        while (len)
                add_chr(a++, *b++, len--);
}

void shl_big(char *big, char n /* 0..3 */, size_t len) {
        big += --len;
        *big = (*big << n) & 15;
        for (--big; len--; --big)
                *big = ((*big << n) & 15) | (big[-1] >> (4 - n));
}

int main() {
        char a[64], b[64];
        const char *num = "3224833640520308023", *p;

        memset(a, 0, sizeof a);

        for (p = num; *p; ++p) {
                shl_big(a, 1, sizeof a);
                memcpy (b, a, sizeof a);
                shl_big(b, 2, sizeof b);
                add_big(a, b, sizeof a);
                add_chr(a, *p - '0', sizeof a);
        }
        p = a + sizeof a;
        while (--p > a && !*p);
        while (p >= a)
                putchar("0123456789ABCDEF"[(int) *p--]);
        putchar('\n');

        return 0;
}

arsi ★★★★★
()

может я его непонимаю
long long atoll(const char *nptr);

или условие что типа 64 бит нету - а в бибилиотеках их тоже нету ?

ae1234 ★★
()
Ответ на: комментарий от Manhunt

>PS по секрету скажу, что можно запросто переводить из одной системы счисления в другу строки произвольной длины
у меня такой секрет на асм-е написан :)

xydo ★★
()
Ответ на: комментарий от AIv

> По сранениию с традицонным сдвиг-с-коррекцией алгоритм имеет кубическую сложность, но поскольку оперирует большими кусками должен быть существенно быстрее (для чисел разумного размера). КРоме того, если так важна производительность алгоритм прекрасно параллелится скажем на GPU;-))))))))

Да, взять O(N^3), запустить на n-ядрах и на больших данных проиграть O(N^2) на одном ядре. Быдлокодеры-такие-быдлокодеры

anonymous
()
Ответ на: комментарий от anonymous

Ну куда нам, дилетантам-быдлокодерам против супер-ананимуса реашющего супер-задачу по переводу десятичного числа из 10^12 знаков в шестнадцатиричное для спасения всего человечества от астероидной атаки 2012 года...

AIv ★★★★★
()

запощу рабочий вариант, вдруг кого поисковик кинет.

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

struct node {
    struct node* next;
    uint32_t data;
};

typedef struct node* nodep;

nodep add_node(nodep n,int reverse) {
    nodep buf = malloc(sizeof(struct node));
    if(buf == NULL) {
        printf("malloc problem\n");
        return NULL;
    }
    if(reverse == 0) {
        n->next = buf;
        buf->next = NULL;
    } else {
        buf->next = n;
    }
    buf->data = 0;
    return buf;
};

nodep create_num(char *s) {
    nodep head = malloc(sizeof(struct node));
    if (head == NULL) {
        return NULL;
    }
    head->next = NULL;
#define MAX_NUM 9
#define NUM_POWER 1000000000
    uint32_t len = strlen(s);
    uint32_t i = 0;
    int needed_pos = len % MAX_NUM;
    if(needed_pos == 0) {
        needed_pos = MAX_NUM;
    }
    uint32_t power = pow(10, needed_pos); /*max 9 numbers*/
    uint32_t data = 0;
    nodep tail = head;
    for(; i < len; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            power /= 10;
            data += (s[i] - '0')*power;
            if (power == 1) {
                tail->data = data;            
                power = NUM_POWER;
                data = 0;
                if(len-i != 1) {
                    tail = add_node(tail, 0);
                }
            }
        } else {
            printf("not a num\n");
            return NULL;
        }
    }
    return head;
}

void print_long_num(nodep head, int hex) {
    nodep buf = head;
    while(buf != NULL) {
        if (hex == 0) {
            if(buf == head) {
                printf("%d", buf->data);
            } else {
                printf("%09d", buf->data);
            }
        } else {
            if(buf == head) {
                printf("%x", buf->data);
            } else {
                printf("%08x", buf->data);
            }
        }
        buf = buf->next;
    }
}

nodep del_node(nodep n) {
    nodep buf = n->next;
    free(n);
    return buf;
}

int div2_and_mod(nodep *head) {
    uint32_t modulo = 0;
    nodep iter = *head;
    while(iter != NULL) {
        uint32_t buf = NUM_POWER*modulo + iter->data;
        modulo = buf % 2;
        iter->data = buf / 2;
        if ((iter == *head) && (iter->data == 0)) {
            iter = del_node(iter);
            *head = iter;
        } else {
            iter = iter->next;
        }
    }
    return modulo;
}

nodep collect_data(nodep head, uint32_t data) {
    nodep buf = add_node(head,1);
    buf->data = data;
    return buf;
}

int main(int argc, char **argv)
{
    if (argc < 2) {
        printf("no number\n");
        return 1;
    }

    printf("start\n");

    nodep head = NULL;
    nodep hexhead = NULL;
    head = create_num(argv[1]);
    print_long_num(head, 0);
    printf("\n");

    uint8_t modulo;
    uint8_t buf_byte = 0;
    uint32_t buf_word = 0;
    uint8_t *pbyte = (uint8_t *)&buf_word;
    int bitcounter = 0;
    int bytecounter = 0;
    while (head != NULL) {
        modulo = div2_and_mod(&head);

        /*x86 specific*/
        buf_byte += (modulo << bitcounter); 
        bitcounter++;
        if (bitcounter == 8 || head == NULL) {
            pbyte[bytecounter] = buf_byte;
            bytecounter += 1;
            bitcounter = 0;
            buf_byte = 0;
        }

        if (bytecounter == 4 || head == NULL) {
            hexhead = collect_data(hexhead, buf_word); 
            bytecounter = 0;
            buf_word = 0;
        }
    }
    print_long_num(hexhead, 1);
    printf("\n");
    printf("end\n");

    /*FIXME release hexhead*/
    return 0;
}
$ gcc numbers.c -lm
$ ./a.out 3224833640520308023
start
3224833640520308023
2cc0e91c32f15537
end
dimon555 ★★★★★
()

запощу правильный вариант - вдруг кто-то решит воспользоваться предыдущим:

#include <gmpxx.h>
#include <iostream>

int main( int argc, char **argv )
{
	if( argc > 1 )
		std::cout << mpz_class( argv[ 1 ] ).get_str( 16 ) << std::endl;
}
aho
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.