1

I'm trying to write my own implementation of the Miller Rabin primality test. I could get it working, but it was very slow for values larger than 64 bits.

In the draft standard ANSI X9.80, "PRIME NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES", they specify behavior up to 1024 bits. My program (on a i7 6700k) would take months at best to run on a single 1024 bit integer.

So I turned to the java implementation of the Miller Rabin test to see what micro-optimizations they used to make the performance tenable.

I've been working my way through their source code, but I've run up against a wall. A lot of the methods they use are private, and testing your codes behavior against code you can't execute is quite difficult.For starters, the first internal method I wanted to call is BigInteger.mod2( int )

I've not programmed extensively in java before, but here's where I got stuck:

import java.lang.reflect.*;
import java.math.BigInteger;

public class HelloWorld
{
    public static void main(String[] args)
    {
        BigInteger a = new BigInteger( "123456789101112" );
        Method mod2 = BigInteger.class.getDeclaredMethod( "mod2", int.class );
        //Class[] arg_types = new Class[1];
        //arg_types[0] = int.class;
        //Method mod2 = BigInteger.class.getDeclaredMethod( "mod2", arg_types );
        mod2.setAccessible( true );
        Object b = mod2.invoke( a, 32 );
        System.out.print( b );
    }
}

Both version of the 'getDeclaredMethod' call throw NoSuchMethodException exceptions. I've looked at the documentation for 'getDeclaredMethod' and they say to do exactly what I'm currently doing when people are asking how to get this function to work.

Any advice on how to invoke the private methods of BigInteger, in particular BigInteger.mod2( int ) would be greatly appreciated. Thanks!

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    Somehow I think you missed the whole point of [private](https://en.oxforddictionaries.com/definition/private) methods. – Joe C Jan 22 '17 at 23:36
  • In what way? I'm trying to write my own implementation of a private method in a java class. I would like to be able to directly call that method in order to compare the output of my code vs. the private method. – Jacob Asmuth Jan 22 '17 at 23:38
  • 1
    Not only that, but any optimisations you may make by using private methods in places like `BigDecimal` will be negated three times over by your use of reflection. – Joe C Jan 22 '17 at 23:39
  • I'm writing my own implementation of BigInteger in C. I'm simply trying to figure out how best to compare the output of the respective implementations. – Jacob Asmuth Jan 22 '17 at 23:40
  • 1
    Then what you should be comparing is the output of the public methods. After all, the private methods may come and go at any time at Java's sole discretion. If, in a future upgrade, they decide to rename or otherwise modify this private method, then you're stuffed. – Joe C Jan 22 '17 at 23:42
  • The output of the public methods is identical. I've already written a full-functional implementation of BigInteger in C. My code is significantly faster than java for simple mathematical operations(add/mult/exp/log/etc). However my code is slower for primality testing, and I'm trying to replicate their optimizations. However, I am unable to compare outputs because the methods are private. – Jacob Asmuth Jan 22 '17 at 23:43
  • Possible duplicate of [Any way to Invoke a private method?](http://stackoverflow.com/questions/880365/any-way-to-invoke-a-private-method) –  Jan 23 '17 at 00:03
  • 1
    Your code works for me. Which JDK are you using? – teppic Jan 23 '17 at 00:15
  • Is this a compilation error or a runtime exception? The code you posted does not compile. Is that the problem you're asking about? – user207421 Jan 23 '17 at 00:38

2 Answers2

4

You are on the right track. The only way to invoke private methods in Java is using reflection API. You are already using it. The only error in your program is that you are not handling the checked exception. Just surround your getDeclaredMethod call and method invocation calls with try-catch and you are good to go.

    BigInteger a = new BigInteger( "123456789101112" );
    Method mod2 = null;
    try {
        mod2 = BigInteger.class.getDeclaredMethod( "mod2", int.class );
    } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    //Class[] arg_types = new Class[1];
    //arg_types[0] = int.class;
    //Method mod2 = BigInteger.class.getDeclaredMethod( "mod2", arg_types );
    mod2.setAccessible( true );
    Object b;
    try {
        b = mod2.invoke( a, 32 );
           System.out.print( b );
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Read the Javadoc for the method Class::getDeclaredMethod. It says that this method throws two exceptions (1) NoSuchMethodException and (2) SecurityException.

Same way, read the Javadoc for the method Method::invoke. It says that this method throws three exceptions (1) IllegalAccessException (2) IllegalArgumentException (3) InvocationTargetException.

The calling method of these methods must catch these exceptions or add a throws clause to its own method signature listing out all these exceptions that it is not handling.

user207421
  • 305,947
  • 44
  • 307
  • 483
VHS
  • 9,534
  • 3
  • 19
  • 43
  • I think this is the right answer. OP doesn't make it clear, but his code doesn't compile, so his actual problem may be an 'unhandled exception' compilation error, and doing this would fix that. – user207421 Jan 23 '17 at 00:40
  • Or add `throws Exception` at your `main` method. If it's for exploring, there's no harm in doing so. For a real app, avoid it! – Olivier Grégoire Jan 23 '17 at 00:47
  • @OlivierGrégoire yes that option is always there. I have already mentioned that in the last line of my answer. Maybe I need to highlight it. Rather than catching these individual exceptions, the OP can simply add `throws` to his `main` method. However I will not recommend this to someone who is trying to learn java the right way. Once he is comfortable with exception handling, he can use `throws` for quick testing. – VHS Jan 23 '17 at 01:38
  • @JacobAsmuth I thought so. A very poorly stated question. – user207421 Jan 23 '17 at 03:33
  • Yup. Apologies. – Jacob Asmuth Jan 23 '17 at 04:02
1

In your example you've failed to handle the checked exceptions that getDeclaredMethod may raise. Change the signature to

public static void main(String[] args) throws Exception {

After that your code should be working. If getDeclaredMethod still raises a NoSuchMethodException then there really isn't a mod2 method in the BigInteger that you're linking against.

This will happen if you run against a JDK with a BigInteger that doesn't have a method with the signature private mod2(int). Gnu classpath, for example, doesn't have one.

teppic
  • 7,051
  • 1
  • 29
  • 35
  • I wish I could mark both answers correct. I'm basically brand new to java, been a C/C++ guy for years... Didn't realize the extra requirements behind exceptions. The other guy did answer first though so I guess he gets the check mark – Jacob Asmuth Jan 23 '17 at 01:09
  • Aye, some days I wish I was still a C guy. A good IDE will take most of the pain out of Java if you have to use it. There are lots of free ones. The intellij community edition is probably the most popular. – teppic Jan 23 '17 at 01:20