C 计算任意大二进制数之和的最快方法是什么
我似乎找不到关于这方面的好文献。具有如下结构的C 计算任意大二进制数之和的最快方法是什么,c,binary,add,C,Binary,Add,我似乎找不到关于这方面的好文献。具有如下结构的BigBinaryNumber(两个虚拟符号位的补码): typedef unsigned char byte; enum Sign {NEGATIVE = (-1), ZERO = 0, POSITIVE = 1}; typedef enum Sign Sign; struct BigBinaryNumber { byte *number; Sign signum; unsigned int size; }; typedef
BigBinaryNumber
(两个虚拟符号位的补码):
typedef unsigned char byte;
enum Sign {NEGATIVE = (-1), ZERO = 0, POSITIVE = 1};
typedef enum Sign Sign;
struct BigBinaryNumber
{
byte *number;
Sign signum;
unsigned int size;
};
typedef struct BigBinaryNumber BigBinaryNumber;
我可以采用小学的方法(即对单个字节求和,然后使用进位进行后续求和),或者使用固定大小的查找表
关于二进制求和的最快方法有什么好的文献吗?加法的最快方法是处理器现有的
add
指令。只要您在内存中合理地排列了数字(例如,您没有向后的位顺序或任何东西),每次从每个数字中加载32位,将它们本机相加,并获得进位就应该非常简单:
uint32_t *word_1 = &number1.number + offset, *word_2 = &number2.number + offset;
uint32_t *word_tgt = &dest.number + offset;
uint64_t sum = *word_1 + *word_2 + carry; // note the type!
*word_tgt = (uint32_t) sum; // truncate
carry = sum >> 32;
请注意,您可能需要添加一些特殊情况来处理数字中的最后一个字节(或确保*number
始终分配4个字节的倍数)
如果您使用的是64位CPU,则可以将其扩展到使用uint64\u t
。不过,溢出没有uint128\u t
,因此您可能需要使用一些技巧来获取进位。技巧是使用本机(或更大的)整数大小
@Daskwuff是一个有钱的人,一次可以浏览多个字节的number
正如所有“最快的方法是什么…”一样,应该分析候选解决方案
下面是一个单类型解决方案,因此可以同时使用最大的类型、本机类型或任何1类型。e、 g.uintmax\u t
或无符号
。进位是通过代码处理的偏好,进位的生成取决于测试加法是否会溢出
typedef unsigned MyInt;
#define MyInt_MAX UINT_MAX
void Add(BigBinaryNumber *a, BigBinaryNumber *b, BigBinaryNumber *sum) {
// Assume same size for a, b, sum.
// Assume memory allocated for sum.
// Assume a->size is a multiple of sizeof(MyInt);
// Assume a->number endian is little and matches platform endian.
// Assume a->alignment matches MyInt alignment.
unsigned int size = a->size;
MyInt* ap = a->number;
MyInt* bp = b->number;
MyInt* sump = sum->number;
int carry = 0;
while (size > 0) {
size -= sizeof(MyInt);
if (carry) {
if (*ap <= (MyInt_MAX - 1 - *bp)) {
carry = 0;
}
*sump++ = *ap++ + *bp++ + 1;
}
else {
if (*ap > (MyInt_MAX - *bp)) {
carry = 1;
}
*sump++ = *ap++ + *bp++;
}
} // end while
// Integer overflow/underflow handling not shown,
// but depend on carry, and the sign of a, b
// Two's complement sign considerations not shown.
}
typedef无符号MyInt;
#定义MyInt_MAX UINT_MAX
无效添加(BigBinaryNumber*a、BigBinaryNumber*b、BigBinaryNumber*sum){
//假设a、b和的大小相同。
//假设为sum分配了内存。
//假设->大小是sizeof(MyInt)的倍数;
//假设->数字endian很小,并且与平台endian匹配。
//假设->对齐方式与MyInt对齐方式匹配。
无符号整数大小=a->size;
MyInt*ap=a->number;
MyInt*bp=b->number;
MyInt*油底壳=总和->数量;
整数进位=0;
而(大小>0){
尺寸-=尺寸(MyInt);
如果(携带){
如果(*ap(MyInt_MAX-*bp)){
进位=1;
}
*油底壳++=*ap++++*bp++;
}
}//结束时
//未显示整数溢出/下溢处理,
//但取决于进位和a,b的符号
//2的补码注意事项未显示。
}
您的代码有一些问题<代码>结构可能应该是struct
;行enum符号{NEGATIVE=(-1),零=0,正=1}
不声明任何内容(仅键入)。*word_1+*word_2
似乎有问题。如果sizeof(uint32\u t)==sizeof(unsigned)
,则*word\u 1+*word\u 2
的任何“执行”都将丢失。也许((uint64_t)*word_1)+*word_2
?一些处理器实现并“带进位的加法”操作(我相信是x86上的“adc”)。它允许您将任意两个任意大的二进制值相加。快速。@Jay同意“带进位添加”等的可用性,但*word\u 1+*word\u 2
并不强制编译器使用。在这部分代码中,只开始添加2个操作数,而不需要保留进位。这只是小学的方法吗?我已经提过了。我同意为了提高速度,您应该使用支持的最大本机整数大小。我可能会测试这比只使用byte
@chux快多少。只需几行汇编程序就可以编写一个循环来添加任意长度的两个二进制块。由于您自己编写,因此可以使用“adc”。我应该说得更清楚。