Умножение очень больших шестнадцатеричных чисел и печать их в C - PullRequest
0 голосов
/ 22 декабря 2019

Я хочу умножить 2 очень больших шестнадцатеричных числа и распечатать их, например, как:

28B2D48D74212E4F x 6734B42C025D5CF7 = 1068547cd3052bbe5688de35695b1239

Поскольку я ожидал, что это будет очень большое число, я использовал unsigned long long int тип:

unsigned long long int x = 0x28B2D48D74212E4F;   
unsigned long long int y = 0x6734B42C025D5CF7; 

и выведите умножение следующим образом:

fprintf(stdout, "%llx\n",  x*y);

То, что я получаю, составляет ровно половину ожидаемого результата:

5688de35695b1239

Почему оно усекает его точно дополовина? Есть ли что-то большее, чем unsigned long long?

1 Ответ

1 голос
/ 22 декабря 2019

Ответ, который вы ищете, не помещается в 64-битную unsigned long long, что является нормальным размером для 64-битной платформы;любое превышение при умножении переполняется и сбрасывается.

Более новые версии GCC поддерживают 128-разрядные целые числа на 64-разрядных компьютерах с __int128unsigned __int128), и это работает:

unsigned long long int x = 0x28B2D48D74212E4FULL;
unsigned long long int y = 0x6734B42C025D5CF7ULL;
unsigned __int128 xy = x * (unsigned __int128)y;

Обратите внимание, что вам необходимо привести один из x или y к более широкому типу, чтобы умножение выполнялось в 128 битах;в противном случае повышение до 128 не будет выполнено до тех пор, пока не произойдет (усеченное) 64-разрядное умножение.

Проблема, насколько я могу сказать, printf() не позволяет легко это сделать,так что вам придется немного покататься.

Здесь есть разумное обсуждение: как напечатать число __uint128_t с помощью gcc?

Но это сработало для меняon:

gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)

#include <stdio.h>

int main()
{
unsigned long long int x = 0x28B2D48D74212E4F;
unsigned long long int y = 0x6734B42C025D5CF7;
unsigned __int128 xy = x * (unsigned __int128)y;

    printf("Result = %016llx%016llx\n",
        (unsigned long long)( xy >> 64),
        (unsigned long long)( xy & 0xFFFFFFFFFFFFFFFFULL));

    return 0;

Важны броски внутри printf:в противном случае сдвиг / маскирование выполняются в 128-битных скалярах, и эти 128 бит помещаются в стек, но тогда каждый %llx ожидает 64 бита.

Обратите внимание, что все это полностью зависит от базовой платформы и является не переносимым ;несомненно, есть способ использовать различные #ifdefs и sizeofs, чтобы сделать его более общим, но, вероятно, не существует супер-удивительного способа сделать это везде.

...