关于O(1)取模快速乘
  • 板块学术版
  • 楼主mcqueen
  • 当前回复12
  • 已保存回复12
  • 发布时间2020/8/27 16:07
  • 上次更新2023/11/5 14:13:20
查看原帖
关于O(1)取模快速乘
50010
mcqueen楼主2020/8/27 16:07
inline ll Mul(ll a,ll b,ll mod)
{
	ll ret=a*b-(ll)((long double)a*b/mod+0.5)*mod;
	return ret<0?ret+mod:ret;
}

以上代码可以在O(1)O(1)的时间内完成两数乘法的取模,其中模数达到了long long级别,且这种方法能够求出正确的结果。

最近复习数论,用到了这个小技巧。我想知道他的原理,于是上网百度了一下,发现这出自一个国集论文。

以下是原文:

为了下面叙述方便,记

A=a*b;
B=(ll)((long double)a*b/mod+0.5)*mod;

现在我已经理解到,对于A,BA,B关于long long 溢出的部分之间的差只可能是0011。那么根据论文的意思,可以如下分类:

  • 如果差为00A,BA,B中long long能保留的部分直接做差是可以求出正确结果的。
  • 如果差为11,按照论文中的解法,ABA-B在long long中保留的部分是个负数。此时我们对答案加上modmod也能求出正确答案。

我对差为11这个分类有些困惑。下面我将举一个例子描述我的困惑:


假设有一个数据类型,他只能存储0到9。

我们用这个快速乘的原理计算3×4%73 \times 4\%7的值。

先算3×43 \times 4。由于他爆了这个数据类型,所以结果是22

再算 3×47×7\left\lfloor\dfrac{3\times 4}{7}\right\rfloor\times 7。 按照快速乘,由于计算这个值得时候用到了long double ,所以会算出精确值77

根据这行代码:

return ret<0?ret+mod:ret;

会算出答案27+mod=27+7=22- 7 + mod= 2- 7+7= 2

可事实上3×4%7=53\times 4\%7 = 5

请问我的理解哪里有问题?


另外,我对long double那一块的原理已经清楚了,不需要再解释了。

请不要有无意义回复,谢谢

2020/8/27 16:07
加载中...