1

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.

Nick Gilbert
  • 4,159
  • 8
  • 43
  • 90
  • 2
    Can you explain what you expect `1 % n` to give you? That looks a little fishy to me. – Dawood ibn Kareem Mar 30 '15 at 02:31
  • Thats not where my problem is, the value of b is wrong before it even gets to that point – Nick Gilbert Mar 30 '15 at 02:35
  • 2
    Just trying to understand what your code is doing, so I can help you. If there are parts here that are not relevant, it would be really useful if you stripped them out and just gave us a [minimal complete example](http://stackoverflow.com/help/mcve) so we don't waste time on the irrelevant parts. – Dawood ibn Kareem Mar 30 '15 at 02:37
  • In this particular case, I guess all anyone needed was `System.out.println(Math.pow(86, 19) % 153);` - and to ask why this doesn't print 86. There was no need to make us read 60-70 lines of fairly opaque code. – Dawood ibn Kareem Mar 30 '15 at 02:44

3 Answers3

2

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
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I was just curious , does this modPow method uses modular exponentiation ? – Tamim Addari Mar 30 '15 at 02:55
  • @TamimAdDari This method is optimised so that it doesn't actually calculate the `pow` part, only the end result. You can try this for large exponents and the time taken is fairly constant. – Peter Lawrey Mar 30 '15 at 03:02
1

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.

Tamim Addari
  • 7,591
  • 9
  • 40
  • 59
0

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

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

tachyonflux
  • 20,103
  • 7
  • 48
  • 67