简体   繁体   中英

Odd math error in Java

I'm writing a program to demonstrate Miller-Rabin probability testing in Java. The code is pretty much done...

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");
        }


    }
}

I've hard-coded 86 as my a value to demonstrate my problem. Where it calculates b for the first time by raising a to the m and taking the modulus n the math is incorrect. Instead of giving a b0 of 86 which is the correct answer to 86^19 % 153 it gives me b0 equals 107. I've checked my values in the debugger and they are right. I've also checked the value of a^m and it gives me 86^19 so the problem occurs with the modulus part. Unfortunately I don't know what is throwing the math off.

double precision in Java (and any IEEE system) has only 15-16 digits of accuracy. If you use a number which is larger than this you will get a representation error.

Most likely what you need to do is use BigInteger which not only handles arbitrary precision but has a method optimised for power & modulus.

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

prints

86

Here , Math.pow returns a double, so taking modulus of a double wouldn't help(Never take a Mod on double, No one is responsible for what you get).

and note that, (89^19) is roughly 2^122, so an unsigned long(2^64-1) wouldn't hold these number. and double has a precision 2^53(never use double to mod, number theory is on integers).Try a smaller value or use the BigInteger class.

The primitive data types have set sizes which can limit their accuracy.

Java has the BigInteger class which may work for your scenario.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM