【问题标题】:Fast way to manually mod a number手动修改数字的快速方法
【发布时间】:2010-11-02 13:04:05
【问题描述】:

我需要能够为非常大的 a 和 b 值计算 (a^b) % c(它们分别在推动限制,当您尝试计算 a^b 时会导致溢出错误)。对于足够小的数字,使用恒等式 (a^b)%c = (a%c)^b%c 有效,但如果 c 太大,这并没有真正的帮助。我写了一个循环来手动进行 mod 操作,一次一个:

private static long no_Overflow_Mod(ulong num_base, ulong num_exponent, ulong mod) 
    {
        long answer = 1;
        for (int x = 0; x < num_exponent; x++)
        {
            answer = (answer * num_base) % mod;
        }
        return answer;
    }

但这需要很长时间。是否有任何简单快捷的方法来执行此操作,而无需实际使用 a 的 b AND 的幂而不使用耗时的循环?如果一切都失败了,我可以创建一个 bool 数组来表示一个巨大的数据类型,并弄清楚如何使用位运算符来做到这一点,但必须有更好的方法。

【问题讨论】:

  • 听起来像是欧拉问题...如果是,您应该在问题中明确说明,而不是试图作弊...
  • 了解 a、b 和 c 的范围可能对我们有所帮助。
  • 这个布尔数组的想法是行不通的。 Bool 数组不是位向量,它们不是打包存储的。另外,您不必依赖直接的硬件数学运算。
  • 我实际上根本没有试图解决这个问题,我需要这个算法来编写我正在编写的加密程序。
  • 这是为了您自己的启迪,还是您打算真正依靠您的算法来保护您的客户免受作恶者的侵害?如果是前者,你去。如果是后者,我强烈建议您重新考虑。

标签: c# algorithm modulo


【解决方案1】:

我猜你正在寻找:http://en.wikipedia.org/wiki/Montgomery_reduction 或基于模幂的更简单方法(来自维基百科)

Bignum modpow(Bignum base, Bignum exponent, Bignum modulus) {

    Bignum result = 1;

    while (exponent > 0) {
        if ((exponent & 1) == 1) {
            // multiply in this bit's contribution while using modulus to keep result small
            result = (result * base) % modulus;
        }
        // move to the next bit of the exponent, square (and mod) the base accordingly
        exponent >>= 1;
        base = (base * base) % modulus;
    }

    return result;
}

【讨论】:

  • 如果模数小于指数,我认为您可以通过取指数的 1 位计数的模数来改进此算法,并且只进行那么多循环迭代。在某些情况下,实际上可以做得比这更好。见凯的回答。
  • 我认为只要 result = 0 result = (result * base) % modules; if (result == 0) 中断;
  • 格式搞砸了我的评论。添加“如果(结果== 0)中断;”计算结果后。
  • 其实在你对 result*base 进行复数之前,检查 base==0 然后再break。
  • "exponent >>= 1;"之后可以在底部突破if exponent == 0 并避免最后的乘法和模法。
【解决方案2】:

快速模幂运算(我认为这就是所谓的)可能会起作用。

给定 a, b, c 和 a^b (mod c): 1. 将 b 写为 2 的幂的和。(如果 b=72,则为 2^6 + 2^3 ) 2. 做: (1) a^2 (mod c) = a* (2) (a*)^2 (mod c) = a* (3) (a*)^2 (mod c) = a* ... (n) (a*)^2 (mod c) = a* 3. 使用上面的 a*,将 a* 乘以您确定的 2 的幂。例如: b = 72,在 3 处使用 a*,在 6 处使用 a*。 a*(3) x a*(6) (mod c) 4. 一次做上一步的乘法,最后得到 a^b % c。

现在,我不知道您将如何处理数据类型。只要你的数据类型可以支持c^2,我想你会没事的。

如果使用字符串,只需创建加法、减法和乘法的字符串版本(不要太难)。这种方法应该足够快。 (并且您可以通过 mod c 开始第 1 步,这样 a 永远不会大于 c)。

编辑:哦,看,Modular Exponentiation 上的 wiki 页面。

【讨论】:

    【解决方案3】:

    这是 java 中快速模幂运算的示例(在较早的答案之一中建议)。将其转换为 C# 应该不会太难

    http://www.math.umn.edu/~garrett/crypto/a01/FastPow.html

    来源...

    http://www.math.umn.edu/~garrett/crypto/a01/FastPow.java

    【讨论】:

      【解决方案4】:

      Python 有 pow(a,b,c) ,它返回 (a**b)%c (只是更快),所以必须有一些聪明的方法来做到这一点。也许他们只是做你提到的身份。

      【讨论】:

        【解决方案5】:

        我建议检查 Decimal 文档并查看它是否满足您的要求,因为它是内置类型并且可以使用 mod 运算符。如果没有,那么您将需要一个任意精度库,例如 java 的 Bignum。

        【讨论】:

        • 不,我说的是,因为他需要找到一个等价物。不读书的方式。
        • 他说喜欢 Java 的 Bignum。不*使用”Java 的 Bignum。鉴于他知道 C# 的十进制类型,他知道问题是关于 C# 的可能是一个不错的选择。
        【解决方案6】:

        您可以尝试“a”分解为足够小的数字。

        如果'a'的因子是'x'、'y'和'z',那么

        a^b = (x^b)(y^b)(z^b)。

        那么你就可以使用你的身份了:(a^b)%c = (a%c)^b%c

        【讨论】:

        • 除了因式分解比模数更难的问题
        • 我会开始在一个循环中划分 a/2 直到它没有均匀划分......然后 a/3 等用素数直到“a”“足够小” a^b 不会溢出。然后按照原海报所述完成操作。
        【解决方案7】:

        在我看来,power 和 mod 之间存在某种关系。幂只是重复乘法,而mod与除法有关。我们知道乘法和除法是相反的,所以通过这种联系,我假设幂和 mod 之间存在相关性。

        例如,取 5 的幂:

        5 % 4 = 1
        25 % 4 = 1
        125 % 4 = 1
        625 % 4 = 1
        ...
        

        模式很明显,对于 b 的所有值,5 ^ b % 4 = 1。

        在这种情况下不太清楚:

        5 % 3 = 2
        25 % 3 = 1
        125 % 3 = 2
        625 % 3 = 1
        3125 % 3 = 2
        15625 % 3 = 1
        78125 % 3 = 2
        ...
        

        但还是有规律的。

        如果你能计算出模式背后的数学,如果你能在不计算实际功率的情况下计算出 mod 的价值,我不会感到惊讶。

        【讨论】:

        • 该模式显而易见且众所周知。这是费马小定理(并且在 OP 中使用了恒等式)。
        • 啊,是的,你是对的,谢谢你指点我。如果您以前考虑过此类问题,那么这很明显,我很感激自己得出了这个想法:)
        • OP 中的费马小定理在哪里?
        • 对不起,我说得太快了。这不是费马。 Kai的帖子和OP都是基本的模乘。
        【解决方案8】:

        你可以试试这个:

        C#:对非常大的数 (> Int64.MaxValue) 执行取模 (mod) 运算
        http://www.del337ed.com/blog/index.php/2009/02/04/c-doing-a-modulus-mod-operation-on-a-very-large-number-int64maxvalue/

        【讨论】:

          【解决方案9】:

          不用自己编写fast modular exponentiation,我能想到的最简单的想法是使用 F# BigInt 类型:Microsoft.FSharp.Math.Types.BigInt,它支持任意大规模的运算 - 包括求幂和模运算。

          它是一个内置类型,将在下一个版本中成为完整 .NET 框架的一部分。您无需使用 F# 即可使用 BitInt - 您可以直接在 C# 中使用它。

          【讨论】:

            【解决方案10】:

            你能分解a、b或c吗? C 是否有已知范围?

            这些是 32 位整数!去看看这个site

            例如,这里是如何获得 n%d 的 mod where d 1>>s (1,2,4,8,...)

              int n = 137;     // numerator
              int d = 32;      // denom d will be one of: 1, 2, 4, 8, 16, 32, ...
              int m;           // m will be n % d
              m = n & (d - 1); 
            

            有 n%d 的代码,其中 d 为 1>>s - 1 (1, 3, 7, 15, 31, ...)

            这只有在 c 很小的情况下才会真正有帮助,就像你说的那样。

            【讨论】:

            • 你的意思是,“其中 d 是 1
            • 是的。我什至不能从另一个网站复制而不会出错!
            【解决方案11】:

            看起来像密码学作业。

            提示:查看Fermat's little theorem

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-07-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多