如果A
和B
类型为uint8_t
且我希望结果C=AxB % N
N
为2 ^ 16,那么我该怎么做呢我不能使用整数(所以我不能在C语言中将N
声明为整数,只能uint8_t
)?
注意:A
,B
和C
存储在uint8
数组中,因此它们被“表达”为uint8
,但它们的值可能更大
答案 0 :(得分:3)
一般来说,没有简单的方法可以做到这一点。
首先,您需要为每个uint8_t块实现A和B之间的乘法运算。请参阅答案here。
2^16
除法真正意味着“忽略”最后16位,“不要使用”最后两位uint8_t
(因为你使用了int数组)。由于你有模数运算符,这意味着相反,所以你只需要得到最后两个uint8_t
。
取uint8
A
的最低a0
(例如a1
和B
)和b0
(说b1
和uint8
}):
将每个a0h = a0 >> 4; ## the same as a0h = a0/16;
a0l = a0 % 16; ## the same as a0l = a0 & 0x0f;
a1h = a1 >> 4;
a1l = a1 % 16;
b0h = b0 >> 4;
b0l = b0 % 16;
b1h = b1 >> 4;
b1l = b1 % 16;
拆分为高低部分
x
首先将下半部分相乘(x = a0l * b0l;
是缓冲区变量)
x
结果的第一部分是s0l
的最后四位,我们称之为s0l = x % 16;
x
c = x>>4;
位的顶部是进位。
uint8
将第一个x = (a0h * b0h) + c;
的较高部分相乘并添加进位。
x
结果的第一部分是s0h
的最后四位,我们称之为s0h = x % 16;
c = x>>4;
。我们需要再次携带。
s0
我们现在可以合并s0 = (s0h << 4) + s0l;
:
x = (a1l * b1l) + c;
s1l = x % 16;
c = x>>4;
x = (a1h * b1h) + c;
s1h = x % 16;
c = x>>4;
s1 = (s1h << 4) + s1l;
对s1做同样的事情(但不要忘记添加进位!):
c
此时您的结果是s1
,s0
和s2
(您需要进行下一次乘法,例如。s3
,s4
,{{1 }},)。正如您的公式所示%(2 ^ 16),您已经得到了结果 - s1
和s2
。如果你必须与其他东西分开,你应该做一些类似于上面的代码,但是为了分裂。在这种情况下,小心地将除以零,它将给你NAN
或其他东西!
你可以将A,B,C和S放在数组中并循环遍历索引,以使代码更清晰。
答案 1 :(得分:2)
这是我的努力。我冒昧地使用更大的整数和指针来循环遍历数组。数字由big-endian顺序的uint8_t
数组表示。所有中间结果都保存在uint8_t
个变量中。如果中间结果可以存储在更宽的整数变量中,则代码可以更有效!
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
static void add_c(uint8_t *r, size_t len_r, uint8_t x)
{
uint8_t o;
while (len_r--) {
o = r[len_r];
r[len_r] += x;
if (o <= r[len_r])
break;
x = 1;
}
}
void multiply(uint8_t *res, size_t len_res,
const uint8_t *a, size_t len_a, const uint8_t *b, size_t len_b)
{
size_t ia, ib, ir;
for (ir = 0; ir < len_res; ir++)
res[ir] = 0;
for (ia = 0; ia < len_a && ia < len_res; ia++) {
uint8_t ah, al, t;
t = a[len_a - ia - 1];
ah = t >> 4;
al = t & 0xf;
for (ib = 0; ib < len_b && ia + ib < len_res; ib++) {
uint8_t bh, bl, x, o, c0, c1;
t = b[len_b - ib - 1];
bh = t >> 4;
bl = t & 0xf;
c0 = al * bl;
c1 = ah * bh;
o = c0;
t = al * bh;
x = (t & 0xf) << 4;
c0 += x;
x = (t >> 4);
c1 += x;
if (o > c0)
c1++;
o = c0;
t = ah * bl;
x = (t & 0xf) << 4;
c0 += x;
x = (t >> 4);
c1 += x;
if (o > c0)
c1++;
add_c(res, len_res - ia - ib, c0);
add_c(res, len_res - ia - ib - 1, c1);
}
}
}
int main(void)
{
uint8_t a[2] = { 0xee, 0xdd };
uint8_t b[2] = { 0xcc, 0xbb };
uint8_t r[4];
multiply(r, sizeof(r), a, sizeof(a), b, sizeof(b));
printf("0x%02X%02X * 0x%02X%02X = 0x%02X%02X%02X%02X\n",
a[0], a[1], b[0], b[1], r[0], r[1], r[2], r[3]);
return 0;
}
输出:
0xEEDD * 0xCCBB = 0xBF06976F