我似乎无法找到关于此的任何好文献。拥有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;
我可以选择小学方法(即将各个字节相加并使用进位进行后续求和),也可以使用固定大小的查找表。
关于最快的二元求和方法有没有好的文献?
答案 0 :(得分:2)
添加数字的最快方法是处理器现有的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_t
。但是,溢出没有uint128_t
,所以你可能不得不使用一些技巧来获取进位。
答案 1 :(得分:0)
“技巧”是使用原生(或可能更大)的整数大小。
@duskwuff只需要花费number
,一次多个字节。
与所有“最快的方式......”一样,应该对候选解决方案进行分析。
Follows是一个一个类型的解决方案,因此可以使用最大类型,本机类型或任何1类型。例如uintmax_t
或unsigned
。进位是通过代码处理的偏好,进位生成取决于测试添加是否会溢出。
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.
}