如何计算模数除法

时间:2013-07-09 21:46:16

标签: c algorithm

我在找到分裂模数时陷入了一个程序。

比如我说:

((a*b*c)/(d*e)) % n

现在,我不能简单地计算表达式,然后将其模数为n,因为乘法和除法在循环中进行,并且该值足够大,即使在long long中也不适合。

  

正如评论中所阐明的那样,n可以被认为是素数。

我发现,对于乘法,我可以很容易地将其计算为:

((a%n*b%n)%n*c%n)%n

但是无法理解如何计算除法部分。

我面临的问题是一个简单的例子:

((7*3*5)/(5*3)) % 11 

上述表达式的值为7

但是如果我计算乘法,模数,那就像:

((7%11)*(3%11))%11 = 10
((10%11)*(5%11))%11 = 6

现在我剩下6/15,我无法生成正确的答案。

有人可以帮助我吗?请通过上面的例子让我理解逻辑。

7 个答案:

答案 0 :(得分:5)

由于11是素数, Z 11 是一个字段。由于15 % 1141/15等于3(因为3 * 4 % 11为1)。因此,6/156 * 37 mod 11。

在你下面的问题评论中,你澄清模数永远是一个素数。

要有效地生成乘法逆的表,您可以将2提升到连续的幂,以查看它生成的值。请注意,在字段 Z p 中,其中p是奇素数,2 p-1 = 1.因此,对于 Z <子> 11

 2^1 = 2
 2^2 = 4
 2^3 = 8
 2^4 = 5
 2^5 = 10
 2^6 = 9
 2^7 = 7
 2^8 = 3
 2^9 = 6

因此5(2 4 )的乘法逆是2 6 (即9)。

因此,您可以像这样生成上表:

power_of_2[0] = 1;
for (int i = 1; i < n; ++i) {
    power_of_2[i] = (2*power_of_2[i-1]) % n;
}

乘法逆表可以这样计算:

mult_inverse[1] = 1;
for (int i = 1; i < n; ++i) {
    mult_inverse[power_of_2[i]] = power_of_2[n-1-i];
}

答案 1 :(得分:2)

在你的例子中,因为15 = 4 mod 11,你实际上最终必须评估(6/4)mod 11.

为了找到一个精确的解决方案,将其重新排列为6 =((x * 4)mod 11),这使得模数除法更加清晰。

如果没有别的,如果模数总是很小,你可以从0迭代到模数1来得到解。

请注意,当模数不是素数时,减少的问题可能有多种解决方案。例如,对于4 =((x * 2)mod 8)有两种解决方案:2和6.这将减少形式问题:

  a = ( (x * b) mod c)

每当b和c不是相对素数时(即每当它们共用一个公约数时)。

类似地,当b和c不是相对素数时,可能没有解决减少问题的方法。例如,3 =((x * 2)mod 8)没有解决方案。只要b和c的最大公约数不分割a就会发生这种情况。

后两种情况是当n 不是素数时,从0到n-1 而不是在乘法下形成一个整数(或等效地,在+和*下面的一个字段)的整数的结果,而是简单地形成 ring 的不太有用的结构。

答案 2 :(得分:2)

我认为问题的方式,应该假设分子可以被分母整除。在这种情况下,素数n的有限域解和关于非素数n的可能扩展和注意的推测基本上是矫枉过正。如果您将所有分子术语和分母术语存储在数组中,则可以迭代地测试(分子术语,分母术语)对并快速找到最大公约数(gcd),然后将分子术语和分母术语除以gcd 。 (找到gcd是一个经典问题,你可以很容易地在线找到一个简单的解决方案。)在最坏的情况下,你将不得不迭代所有可能的对,但在某些时候,如果分母确实划分了分子,那么你最终会留下减少的分子项,所有分母项都是1.然后你就可以按照你描述的方式应用乘法(避免溢出)。

答案 3 :(得分:2)

当n为素数时,除以整数b只是乘以b的逆。那就是:

(a / b) mod n = (a * inv(b)) mod n

,其中

inv(b) = (b ^ (n - 2)) mod n

使用Exponentiation by squaring算法可以在O(log(n))时间内完成计算inv(b)。这是代码:

int inv(int b, int n)
{
    int r = 1, m = n - 2;
    while (m)
    {
        if (m & 1) r = (long long)r * b % n;
        b = (long long)b * b % n;
        m >>= 1;
    }
    return r;
}

为什么会这样?根据费马的小定理,如果n是素数,则对于任何正整数b,b ^(n - 1)mod n = 1。因此我们有inv(b)* b mod n = 1。

查找inv(b)的另一个解决方案是Extended Euclidean algorithm,需要更多代码才能实现。

答案 4 :(得分:0)

我认为你可以分发像

这样的部门
z = d*e/3
(a/z)*(b/z)*(c/z) % n

仅保留整数除法问题。

答案 5 :(得分:0)

我认为你遇到的问题是你选择的问题太简单了。在那种情况下,答案是7,但如果a * b * c不能被c * d整除,怎么办?您应该首先查看如何使用模数进行除法,您应该清楚:)

答案 6 :(得分:0)

不是划分,而是用乘法反转来思考。对于mod-n系统中的每个数字,如果满足某些条件,则应该存在反转。对于d和e,找到那些反转,然后它们只是成倍增加。通过划分找不到反转!那里有很多信息......