避免溢出工作模型p
Avoiding overflow working modulo p
作为大学作业的一部分,我必须在椭圆曲线p = 2^255-19上在C标量乘法中实现。使用原始类型(未签名长(。
但是,如果a和b是两个整数模块,则有溢出计算A*b的风险。我不确定如何避免这种情况。以下代码正确吗?
long a = ...;
long b = ...;
long c = (a * b) % p;
或我宁愿先施放A和B?
long a = ...;
long b = ...;
long long a1 = (long long) a;
long long b1 = (long long) b;
long c = (long) ((a1 * b1) % p);
我也一直在思考或与漫长的长时间合作。
整个操作(乘法(正在牢记操作数的类型。您乘以两个long
变量,结果如果大于long
变量所能保留的结果,则会溢出。
((a%p)*(b%p))%p
这给出了一个保护它围绕p
包裹的保护,但是在较早的情况下仍说出的话仍然可以-(a%p)*(b%p)
仍然可以溢出。(考虑到a
,b
是类型long
(。
如果将long
的值存储在long long
中,则无需施放。但是,是的,当乘法得出的值大于long long
时,结果将溢出。
给您一个澄清: -
long a,b;
..
long long p = (a*b)%m;
这无济于事。完成后的乘法为long
算术。我们存储最终结果的位置都没关系。这取决于操作数的类型。
现在看这个
long c = (long) ((a1 * b1) % p);
这里的结果将是两个long long
乘法,并且将基于最大值long long
溢出,但是当您将其分配给long
时,仍然有可能溢出。
如果p
是255
字节,您将无法意识到使用内置类型long
或使用32
或64
BIT系统的内置类型的内置类型。当我们拥有512
位系统时,这肯定是可能的。还需要注意的一件事是何时p=2
255 -19
,那么与之进行模块化算术几乎没有任何实用性。
如果sizeof long
如ILP64和LP64中的sizeof long long
等于CC_27,则使用long
,并且long long
不会给您带来任何结果。但是,如果sizeof long long
大于sizeof long
,则可以在long long
中保存操作数以防止乘法的溢出。
另一种解决方法是编写自己的大整数库(多个精确整数库(或使用已经存在的大整数库(也许是这样(。这个想法围绕以下事实:较大的类型是使用像char
这样的简单的东西实现的,然后在其上进行操作。这是一个实现问题,围绕同一主题有许多实现。
具有255 位整数要求,标准操作和C库不足。
在一般算法中遵循以编写自己的模块化乘法。
myint mod(myint a, myint m);
myint add(myint a, myint b); // this may overflow
int cmp(myint a, myint b);
int isodd(myint a);
myint halve(myint a);
// (a+b)%mod
myint addmodmax(myint a, myint b, myint m) {
myint sum = add(a,b);
if (cmp(sum,a) < 0) {
sum = add(mod(add(sum, 1),m), mod(myint_MAX,m)); // These additions do not overflow
}
return mod(sum, m);
}
// (a*b)%mod
myint mulmodmax(myint a, myint b, myint m) {
myint prod = 0;
while (cmp(b,0) > 0) {
if (isodd(b)) {
prod = addmodmax(prod, a, m);
}
b = halve(b);
a = addmodmax(a, a, m);
}
return prod;
}
我最近遇到了同样的问题。
首先,我将假设您的意思是32- bit 整数(阅读您的评论后(,但我认为这也适用于大整数(因为进行天真的乘法意味着要加倍单词大小,也将很慢(。
选项1
我们使用以下属性:
命题。 a*b mod m = (a - m)*(b - m) mod m
证明。
(a - m)*(b - m) mod m =
(a*b - (a+b)*m + m^2) mod m =
(a*b mod m - ((a+b) + m)*m mod m) mod m =
(a*b mod m) mod m = a*b mod m
q.e.d。
此外,如果a,b大约m,则(a - m)*(b - m) mod m = (a - m)*(b - m)
。您需要解决a,b> m的何时,但是我认为(m - a)*(m - b) mod m = a*b mod m
的有效性是上述命题的必然性。当然,当差异很大时,不要这样做(小模量,大a或b;反之亦然(,或者会溢出。
选项2
来自Wikipedia
uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t m)
{
uint64_t d = 0, mp2 = m >> 1;
int i;
if (a >= m) a %= m;
if (b >= m) b %= m;
for (i = 0; i < 64; ++i)
{
d = (d > mp2) ? (d << 1) - m : d << 1;
if (a & 0x8000000000000000ULL)
d += b;
if (d >= m) d -= m;
a <<= 1;
}
return d;
}
以及假设long double
和32或64位整数(不是任意精度(您可以在不同类型的大多数重要位置上利用机器优先级:
在计算机体系结构上,可以使用至少64位Mantissa(例如大多数X86 C编译器的长双重类型(的扩展精度格式,以下例程要比任何算法解决方案都快,通过采用一个技巧,该技巧是通过硬件,浮点乘法会导致产品的最重要位,而整数乘法会导致保留最低的位置
和:
uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t m)
{
long double x;
uint64_t c;
int64_t r;
if (a >= m) a %= m;
if (b >= m) b %= m;
x = a;
c = x * b / m;
r = (int64_t)(a * b - c * m) % (int64_t)m;
return r < 0 ? r + m : r;
}
保证这些不会溢出。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- QTableView:endMoveRows在模型中重置水平页眉大小
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- 将IBM Rhapsody模型集成到VS 2019中
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 旋转模型矩阵时的形状失真
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 避免溢出工作模型p
- 在2D伊辛模型上工作。C++新手。我在第 23 行收到错误"expected unqualified-id before '{' token"
- 在C++中部署GBM模型|获取Predict.GBM以在R之外工作
- C++14记忆模型如何在内部工作以及它与培根的垃圾收集统一理论的比较
- resizeColumnToContent不能与自定义模型和委托一起工作