【问题标题】:Odd math error in JavaJava中的奇怪数学错误
【发布时间】:2015-06-02 22:54:03
【问题描述】:

我正在编写一个程序来演示 Java 中的 Miller-Rabin 概率测试。代码差不多完成了……

import java.util.Random;
import java.util.Scanner;

/**
 * Program to demonstrate Miller-Rabin primality testing
 * 
 * @author Nick Gilbert
 */
public class MillerRabin
{
    public static void main(String[] args)
    {
        //Setting up for algorithm
        Scanner in = new Scanner(System.in);
        Random rn = new Random();
        int n = 0, k = 0, m = 0, a = 0;
        double b = 0;
        boolean probablyPrime = false;

        //Asking user for an odd n
        do
        {
            System.out.print("Enter an odd number to test for primality: ");
            n = in.nextInt();
        }
        while(n % 2 == 0);

        //Calculating k and m
        m = n - 1;
        while(m % 2 == 0)
        {
            m /= 2;
            k++;
        }

        //Generating random a
        //a = rn.nextInt(n-1);

        //Outputting numbers that will be used in algorithm
        System.out.println("k = " + k);
        System.out.println("m = " + m);
        System.out.println();
        a = 86;
        System.out.println("A = " + a);

        //Running the algorithm
        //b_{0}
        b = Math.pow(a, m) % n;
        System.out.println("b0 = " + b);
        if(Math.abs(b) == Math.abs(1 % n)) //Dealing with +/- case via absolute value
        {
            probablyPrime = true;
        }
        else
        {
            //b_{1-(k-1)}
            for(int i = 1; i < k; i++) //Going to k-1
            {
                b = Math.pow(b, 2) % n;
                System.out.println("b" + i + " = " + b);
                if(Math.abs(b) == Math.abs(1 % n)) //Dealing with +/- case via absolute value
                {
                    probablyPrime = true;
                    break;
                }
            }
        }

        //Printing result
        if(probablyPrime)
        {
            System.out.println("Probably Prime");
        }
        else
        {
            System.out.println("Definitely Composite");
        }


    }
}

我已经硬编码 86 作为我的值来证明我的问题。在第一次通过将 a 提高到 m 并取模数 n 来计算 b 的地方,数学是不正确的。而不是给出 86 的 b0 是 86^19 % 153 的正确答案,而是给我 b0 等于 107。我已经在调试器中检查了我的值,它们是正确的。我还检查了 a^m 的值,它给了我 86^19 所以问题出现在模数部分。不幸的是,我不知道是什么让数学失败了。

【问题讨论】:

  • 你能解释一下你期望1 % n给你什么吗?我觉得这有点可疑。
  • 这不是我的问题所在,b 的值在它到达那个点之前就已经错了
  • 只是想了解您的代码在做什么,所以我可以帮助您。如果这里有不相关的部分,如果您将它们剥离出来并给我们一个minimal complete example,这样我们就不会在不相关的部分上浪费时间。
  • 在这种特殊情况下,我想所有需要的人都是System.out.println(Math.pow(86, 19) % 153); - 并问为什么这不打印 86。没有必要让我们阅读 60-70 行相当不透明的代码.

标签: java primes primality-test


【解决方案1】:

Here,Math.pow 返回一个双精度数,因此取双精度数的模数不会有帮助(永远不要对双精度数使用 Mod,没有人对你得到的结果负责)。

请注意,(89^19) 大约是 2^122,因此 unsigned long(2^64-1) 不会保存这些数字。而 double 的精度为 2^53(永远不要使用 double 来 mod,数论是整数)。尝试更小的值或使用 BigInteger 类。

【讨论】:

  • Double 只有 2^53 精度,因为高位用于符号和指数。
【解决方案2】:

double 在 Java(和任何 IEEE 系统)中的精度只有 15-16 位精度。如果使用大于此的数字,则会出现表示错误。

您最有可能需要做的是使用 BigInteger,它不仅可以处理任意精度,而且还具有针对幂和模数优化的方法。

// 86^19 % 153
BigInteger result = BigInteger.valueOf(86).modPow(BigInteger.valueOf(19), BigInteger.valueOf(153));
System.out.println(result);

打印

86

【讨论】:

  • 我只是好奇,这个 modPow 方法是否使用模幂运算?
  • @TamimAdDari 此方法经过优化,因此它实际上并不计算 pow 部分,只计算最终结果。您可以尝试对大指数进行此操作,并且所花费的时间相当稳定。
【解决方案3】:

primitive data types 设置了可能会限制其准确性的大小。

Java 有 BigInteger 类,它可能适用于您的场景。

【讨论】:

    猜你喜欢
    • 2014-06-03
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    相关资源
    最近更新 更多