-2

Here is my code:

  import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
import java.security.SecureRandom;

public class Solution {
    static BigDecimal result;
    static Double y = 0.0;
    static int o;
    static int[] factors = new int[1];
    static int current = 0;
    public static void main(String[] args) {
        Scanner a1 = new Scanner(System.in);
        int b = a1.nextInt();
        o = b;
        result = new BigDecimal(Integer.valueOf(b));
        BigInteger N = new BigInteger(Integer.toString(b - 1));
        factor(N);
        boolean isPrimitive = true;

        for (int i1 = 2; i1 < 10000;i1++) {
        isPrimitive = true;
        //System.out.println("Enter the value of a large prime no");
        BigInteger value = new BigInteger(String.valueOf(o-1));
        //System.out.println("\nEnter the value of alpha");
        BigInteger checking = new BigInteger(String.valueOf(i1));
        BigInteger bigValue = new BigInteger(String.valueOf(o));

        for(int i=0;i<factors.length;i++)
        {
            BigInteger temp = checking.pow(factors[i]);
           // System.out.println("checking "+i1+": "+temp+" mod "+o+" = " + (temp.mod(new BigInteger(String.valueOf(o)))));
         if ((temp.mod(bigValue)).equals(BigInteger.ONE)) {
             isPrimitive = false;
             break;
         }
        }
        if(isPrimitive) {
            System.out.print(i1+" ");
            break;
        }
        else{
            //System.out.println("not primitive roots");
        }

        }
        System.out.println(result.toBigInteger());


    }



    private final static BigInteger ZERO = new BigInteger("0");
    private final static BigInteger ONE = new BigInteger("1");
    private final static BigInteger TWO = new BigInteger("2");
    private final static SecureRandom random = new SecureRandom();

    public static BigInteger rho(BigInteger N) {
        BigInteger divisor;
        BigInteger c = new BigInteger(N.bitLength(), random);
        BigInteger x = new BigInteger(N.bitLength(), random);
        BigInteger xx = x;

        // check divisibility by 2
        if (N.mod(TWO).compareTo(ZERO) == 0) return TWO;

        do {
            x = x.multiply(x).mod(N).add(c).mod(N);
            xx = xx.multiply(xx).mod(N).add(c).mod(N);
            xx = xx.multiply(xx).mod(N).add(c).mod(N);
            divisor = x.subtract(xx).gcd(N);
        } while ((divisor.compareTo(ONE)) == 0);

        return divisor;
    }

    public static void factor(BigInteger N) {

        //System.out.println("result = "+result);
        if (N.compareTo(ONE) == 0) return;
        if (N.isProbablePrime(20)) {
           // System.out.println("n = "+N);
            if ((N.doubleValue() != (y)) &&N.doubleValue() != (1.0) ) {
                // System.out.println("j = "+String.valueOf(1.0 - (1.0/(N.doubleValue()))));
                BigDecimal j = new BigDecimal(String.valueOf(1.0 - (1.0/(N.doubleValue()))));
                //System.out.println("result = " +result+" * "+j);
                result = new BigDecimal(String.valueOf(result.doubleValue() * j.doubleValue()));
                //System.out.println(result.multiply(j));

                //System.out.println((String.valueOf(1.0 - (1.0/(N.doubleValue())))));

                y = N.doubleValue();
                if (current == factors.length) {
                    int[] temp = new int[factors.length+1]; 
                    for (int i = 0; i < factors.length;i++) {
                        temp[i] = factors[i];
                    }
                    factors = temp;

                }
                factors[current] = o/y.intValue();
               // System.out.println(o+"/"+y.intValue());
                current++;


                //System.out.println("result = "+result);
            }

            return;
        }
        BigInteger divisor = rho(N);
        factor(divisor);
        factor(N.divide(divisor));
    }



}

I am trying to find the first primitive root of a prime number, then the amount of primitive roots it has. Finding the amount is no problem for any number, but finding the first number is supposed to work for any number up to 1 billion on a certain system for on which other people have been successful. It works for all values up to around a million, but it doesn't work for 999994267. I don't know how I can possibly optimize this further. I have spent maybe 18 hours on this. I honestly can't figure this out. Any suggestions?

Math Explanation: It takes the factors of the given number o, and tests every number from 2 if it's o/factor[1,2,...] is = 1, if none of o's factors are, it breaks and prints the number.

PS. It is possible, as many other people have done it on the same system.

Arseniy
  • 19
  • 1
  • 6

1 Answers1

-1

Ok so thanks to @IgorNikolaev above in the comments of my question I have figured out my problem and solved it. To fully optimize a modPow operation you need to use modular arithmetic.

Here are some links he provided which greatly helped:

en.wikipedia.org/wiki/Modular_arithmetic

en.wikipedia.org/wiki/Modular_exponentiation

And here is the code I wrote based on those links:

private static BigInteger fastModPow(BigInteger base, BigInteger exponent, final BigInteger modulo) {

    BigInteger result = BigInteger.ONE;
    while (exponent.compareTo(BigInteger.ZERO) > 0) {
        if (exponent.testBit(0)) 
            result = (result.multiply(base)).mod(modulo);
        exponent = exponent.shiftRight(1);
        base = (base.multiply(base)).mod(modulo);
    }
    return result.mod(modulo);
}

As you will see in the first link, it sort-of "wraps around" to find the mod of a power.

Thanks for everyones help.

Arseniy
  • 19
  • 1
  • 6
  • This is pointless as the modPow is already a BigInteger method and is called, wait for it, ... [`modPow`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigInteger.html#modPow(java.math.BigInteger,java.math.BigInteger)) – President James K. Polk Feb 01 '22 at 11:05