【问题标题】:Calculating Eulers Totient Function for very large numbers JAVA计算非常大的数字的欧拉总函数JAVA
【发布时间】:2012-11-04 07:22:10
【问题描述】:

我已经设法使 Eulers Totient Function 的一个版本工作,尽管它适用于较小的数字(与我需要它计算的 1024 位数字相比,这里较小)

我的版本在这里 -

public static BigInteger eulerTotientBigInt(BigInteger calculate) { 

    BigInteger count = new BigInteger("0");
    for(BigInteger i = new BigInteger("1"); i.compareTo(calculate) < 0; i = i.add(BigInteger.ONE)) { 
        BigInteger check = GCD(calculate,i);

        if(check.compareTo(BigInteger.ONE)==0)  {//coprime
            count = count.add(BigInteger.ONE);          
        }
    }
    return count;
}

虽然这适用于较小的数字,但它的工作原理是遍历从 1 到正在计算的数字的所有可能值。对于大的 BigInteger,这是完全不可行的。

我已经读过,可以在每次迭代中除以数字,从而无需逐个遍历它们。我只是不确定我应该除以什么(我看过的一些例子是用 C 语言并使用 long 和平方根 - 据我所知,我无法计算出准确的BigInteger 的平方根。我还想知道,如果对于像这样的模运算,函数是否需要包含一个参数来说明 mod 是什么。我完全不确定,所以任何建议都非常感谢。

任何人都可以在这里指出正确的方向吗?

PS 当我找到modifying Euler Totient Function 时,我删除了这个问题。我对其进行了调整以与 BigIntegers 一起使用 -

public static BigInteger etfBig(BigInteger n) {

    BigInteger result = n;
    BigInteger i;

    for(i = new BigInteger("2"); (i.multiply(i)).compareTo(n) <= 0; i = i.add(BigInteger.ONE)) {
         if((n.mod(i)).compareTo(BigInteger.ZERO) == 0) 
         result = result.divide(i);
         while(n.mod(i).compareTo(BigInteger.ZERO)== 0 ) 
             n = n.divide(i);
     }      
 if(n.compareTo(BigInteger.ONE) > 0)
 result = result.subtract((result.divide(n)));
 return result;
}

它确实给出了准确的结果,当传递一个 1024 位数字时,它会永远运行(我仍然不确定它是否完成,它已经运行了 20 分钟)。

【问题讨论】:

  • 有些过于简单化了,您必须能够分解 n 来计算 1024 位数字的总函数。在涉及计算全部函数的加密协议中,您已经有了质因数分解。

标签: java optimization cryptography public-key-encryption factorization


【解决方案1】:

totient 函数有一个公式,它需要 n 的素数分解。 看here

公式为:

phi(n) = n * (p1 - 1) / p1 * (p2 - 1) / p2 ....
were p1, p2, etc. are all the prime divisors of n.

请注意,您只需要 BigInteger,而不需要浮点数,因为除法始终是精确的。

所以现在问题被简化为找到所有素因子,这比迭代要好。

这是整个解决方案:

int n;  //this is the number you want to find the totient of
int tot = n; //this will be the totient at the end of the sample
for (int p = 2; p*p <= n; p++)
{
    if (n%p==0)
    {
        tot /= p;
        tot *= (p-1);
        while ( n % p == 0 ) 
            n /= p;
    }
}
if ( n > 1 ) { // now n is the largest prime divisor
    tot /= n;
    tot *= (n-1);
}

【讨论】:

  • 这是否意味着如果我将 n-1 用于 p1(n 是素数,所以 phi n = n-1),那么 p2 等将是我正在寻找的素数?还是会返回素数除数?
  • 我的意思是,你如何得到 p1 p2 等,n 的主要除数?或者它们是通过计算你上面提到的 phi(n) 给出的。
  • 虽然我很欣赏这个解决方案,但您发布的那个是我使用的原版 - 我无法将 1024 位数字放入 int 中。
  • 欧拉定理更关心 n 的值和 phi(n) 所以如果你得到 n 的乘积是素数。对于 x^phi(n) mod n ...,任何正整数 x 都应该等于 1。phi(n) 是产生 n ...的两个素数...就像 n = pg。 phi(n) = (p-1)*(g-1)。
【解决方案2】:

您尝试编写的算法等效于分解参数n,这意味着您应该期望它永远运行,实际上直到您的计算机死机或您死机为止。有关更多信息,请参阅 mathoverflow 中的这篇文章:How hard is it to compute the Euler totient function?

另一方面,如果您想要某个已分解的大数的 totient 的值,请将参数作为(素数,指数)对的序列传递。

【讨论】:

  • 你完全正确,谢谢。让我震惊的是我们的笔记中有一行说 N = 55 = 5 x 11。我读到这意味着他已经分解了 55,但现在我看到你的答案,很明显他选择了两个互质数来生成 N。感谢您的帮助:)
【解决方案3】:

etfBig 方法有问题。
欧拉的乘积公式是所有因子的 n*((factor-1)/factor)。 注意:Petar 的代码如下:

tot /= p; tot *= (p-1);

在etfBig方法中,替换result = result.divide(i);

result = result.multiply(i.subtract(BigInteger.ONE)).divide(i);

从 2 到 200 的测试会产生与常规算法相同的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 2020-04-19
    • 2015-02-15
    • 1970-01-01
    相关资源
    最近更新 更多