首页 > 解决方案 > 将非常大的十六进制数相乘并在 C 中打印它们

问题描述

我想将 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吗?

标签: cunsigned-long-long-int

解决方案


您正在寻找的响应不适合 64-bit unsigned long long,这是 64-bit 平台上的正常大小;乘法过程中的任何多余部分都会溢出并丢弃。

较新版本的 GCC 确实支持64 位机器上的128位整数__int128(and unsigned __int128),这有效:

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

请注意,您必须将其中一个xy转换为更宽的类型,以便乘法以 128 位完成;否则,直到(截断的)64 位乘法之后才会提升到 128。

问题是,据我所知,printf()没有办法轻松做到这一点,所以你将不得不自己动手。

这里有一些合理的讨论:how to print __uint128_t number using gcc?

但这对我有用:

gcc (GCC) 4.8.5 20150623 (红帽 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 使其更通用,但可能没有超级棒的方法可以让这项工作无处不在。


推荐阅读