I'm trying to solve Project Euler problem #16, where I need to sum all the digits of 2^1000. I've gotten stuck dealing with such a big number. My program worked for any number below 10^16, but failed afterwards. This told me that my logic was correct. I went ahead and converted all variables and methods to BigDecimal, but now the program does not run properly. It compiles as it is and there is no error; it just does not terminate. Does anyone have an idea on where I went wrong here?
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Powerdigitsum {
private static final BigDecimal one = new BigDecimal("1");
private static final BigDecimal ten = new BigDecimal("10");
private static BigDecimal sumofDigits(BigDecimal n){
BigDecimal sum = new BigDecimal("0");
while(n.compareTo(one) == 1 || n.compareTo(one) == 0){
sum.add(n.remainder(ten));
n.divide(ten);
n = n.setScale(0, RoundingMode.FLOOR);
}
return sum;
}
public static void main(String[] args) {
final double the_number = Math.pow(2,1000);
final double test = 15;
final BigDecimal two_to_the_thousandth_power = new BigDecimal(test);
System.out.println(sumofDigits(two_to_the_thousandth_power));
}
}
Just use BigInteger properly:
BigInteger a = new BigInteger("2").pow(1000);
The whole method is kinda wrong. See this:
private static BigInteger sumOfDigits(BigInteger n) {
BigInteger sum = BigInteger.ZERO;
while (n.compareTo(BigInteger.ZERO) == 1) {
sum = sum.add(n.remainder(ten));
n = n.divide(ten);
}
return sum;
}
You needed to compare to zero, not one. And you need to assign the values for BigIntegers and BigDecimals, their methods do nothing on their own, the instances of those classes are immutable.
For integers, it's generally better to use BigInteger. The decimal part (that gets there from dividing) is just thrown away.
final double the_number = Math.pow(2,1000);
This won't work because the_number is not large enought to take the result. You need to convert the pow call to BigInteger:
BigInteger result = new BigInteger("2").pow(1000);
But be aware.. this can take some time..
Don't use the BigDecimal(double) constructor: it is limited by the double primitive type, which cannot represent 2^1000.
You can use a BigInteger. Something along these lines should work (probably suboptimal, but...):
public static void main(final String... args)
{
// 2^1000
final BigInteger oneTo2000 = BigInteger.ONE.shiftLeft(1000);
BigInteger digitSum = BigInteger.ZERO;
// We don't want to split against the empty string, the first element would be ""
for (final String digit: oneTo2000.toString().split("(?<=.)"))
digitSum = digitSum.add(new BigInteger(digit));
System.out.println(digitSum);
}
public class SumofDigitsPow {
public static void main(String[] args) {
//2(2^1000)
String temp = BigInteger.ONE.shiftLeft(1000).toString();
int sum = 0;
for(int i=0;i<temp.length();i++){
sum+= temp.charAt(i) - '0';
}
System.out.println(Integer.toString(sum));
}
}
java.math.BigInteger.shiftLeft(int n) method returns a BigInteger whose value is (this << n),So you can get the answer by using BigInteger and LeftShift Method
import java.math.BigInteger;
public class Problem16 {
public static void main(String[] args) {
BigInteger number2 = new BigInteger("2");
BigInteger number3 = new BigInteger("0");
number3 =number2.pow(1000);
String str = number3.toString();
BigInteger sum = new BigInteger("0");
for(int i=0; i<str.length(); i++)
{
char c= str.charAt(i);
int value = Character.getNumericValue(c);
BigInteger value2 = new BigInteger(Integer.toString(value));
sum =sum.add(value2) ;
}
System.out.println(sum);
}
}
IF YOU THINK BIGINTEGER IS CHEATING AND/OR don't feel like using it/learning how to use it, this algorithm is the way to go.
Think about how you would calculate 2^1000 by hand. You'd start with 2^1 and multiply by two repeatedly. Now notice that the number of digits of powers of two increase by 1 for AT LEAST every 3 powers (could be after 4 powers like with 1024 to 8192). So make a jagged 2D array like this
int a[][]= new int[1000][];
for(int i=0;i<1000;i++)
{
a[i]= new int[1+(i/3)];
}
Then initialize a[0][0] to 2. After this, you want to write a for loop such that each row is filled from the rightmost spot. So make two variables "digit" and "carry". Digit is the number that you will input into the row you're working on, and the carry is the one you're going to take to the next calculation and add to the product of 2 and whatever digit you're multiplying it with. Be careful with the order you update digit and carry and reinitialize them to zero after every calculation. I think the hardest part is coming up with the limits for the for loop, so that it fits with the every 3 powers thing. You can make this simpler by just making a triangular jagged array that increments by one every row. I did it like this though. Here's my whole code.
import java.util.*;
public class ProjectEuler16
{
public static void main(String[] args)
{
long t1=System.currentTimeMillis();
ProjectEuler16 obj = new ProjectEuler16();
System.out.println(obj.bigNumHandler());
long t2= System.currentTimeMillis();
System.out.println(t2-t1);
}
int bigNumHandler()
{
int a[][] = new int[1000][];
for(int i=0;i<1000;i++)
{
a[i]= new int[1+(i/3)];
}
a[0][0]=2;
for(int i=1;i<1000;i++)
{
int carry=0;
int digit=0;
int f=0;
if(i%3==0)
{
f=1;
}
for(int j=a[i-1].length-1+f;j>=0;j--)
{
if(j==0&f==1)
{
a[i][0]=carry;
}
else
{
digit=((2*a[i-1][j-f])+carry)%10;
carry=((2*a[i-1][j-f])+carry)/10;
a[i][j]=digit;
}
}
}
int sum=0;
for(int k=0;k<a[999].length;k++)
{
sum=sum+a[999][k];
}
return sum;
}
}
Note that the last row lists the digits for 2^1000.I think you can figure out how to sum the digits. The program took about 5 seconds to come up with the answer.
solution::::
import java.math.BigInteger;
public class PR9 {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
BigInteger zero=BigInteger.valueOf(0);
BigInteger ten=BigInteger.valueOf(10);
BigInteger sum=zero;
BigInteger a = new BigInteger("2").pow(1000);
while(a.compareTo(zero)>0){
sum=sum.add(a.mod(ten));
a=a.divide(ten);
}
System.out.println(sum);
}
}
output:::::
1366
import java.math.BigInteger;
public class P16 {
public static BigInteger digitSum(int n) {
BigInteger sum = BigInteger.ZERO;
BigInteger number = new BigInteger("2").pow(n);
while (number.compareTo(BigInteger.ZERO) == 1) {
BigInteger remainder = number.remainder(BigInteger.TEN);
sum = sum.add(remainder);
number = number.divide(BigInteger.TEN);
}
return sum;
}
public static void main(String[] args) {
final double START = System.nanoTime();
System.out.println(digitSum(Integer.parseInt(args[0])));
final double DURATION = System.nanoTime() - START;
System.out.println("Duration: " + DURATION / 1000000 + "ms.");
}
}
While there maybe a way of solving this problem without the use of BigIntegers, it is clear that they make the code run way faster.
Mine only took about 4ms to find an answer.
Related
I am trying to generate unique random number using the below function. Whenerver I run my code in a loop of 1000, it generates duplicate number also.
Code
private static String randomize() {
int count = 10;
List<Integer> digits = createList(count);
Collections.shuffle(digits); // this re-arranges the elements in the list
return listToString(digits);
}
private static <T> String listToString(List<T> list) {
StringBuilder result = new StringBuilder();
for (T object : list) {
result.append(object);
}
return result.toString();
}
private static List<Integer> createList(int size) {
List<Integer> result = new ArrayList<Integer>(size);
for (int i = 0; i < size; i++) {
result.add(i);
}
return result;
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
String strName = randomize();
System.out.println(strName);
}
I searched a lot in google and tried ThreadLocal also, it did not help me. Any help or guide on this will be really helpful. My idea is to generate 10 digit non-repeating random number within a loop.
You're not really generating random numbers, are you? You're generating random permutations of the 10 unique digits [0..9]. (e.g. "0123456789", "9834105672", etc.) Since there are only 3268800 (10!) unique permutations, you have a decent chance of hitting a duplicate with 1000 tries.
(I haven't worked out the math, but since 1000^2 is within an order of magnitude of 10!, my intuition tells me there's at least a 10% chance of a duplicate in any given set. Google "birthday paradox" for details.)
What you want to do, and what #Andrei is trying to explain, is to check/store the result every time you call randomize() to make sure you don't have duplicates. Roughly:
public static void main(String[] args) {
Set<String> results = new HashSet<>(1000);
while (results.size() < 1000) {
String strName = randomize();
if (!results.contains(strName)) {
System.out.println(strName);
results.add(strName);
}
}
}
Unless of course you actually want a set of random numbers:
public static void main(String[] args) {
Set<Long> results = new HashSet<>(1000);
while (results.size() < 1000) {
// Random number on [1E9..1E10]
long random = (long) (Random.nextDouble() * 900000000L) + 100000000L;
if (!results.contains(random)) {
System.out.println(random);
results.add(random);
}
}
}
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.
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.
Problem
In the above problem, given a positive integer n it is intended to find the sum of all the digits in n!. So here is my java code for it:
public static void main (String[] args) throws java.lang.Exception
{
Scanner sc = new Scanner(System.in);
while(sc.hasNext())
{
int n = sc.nextInt();
BigInteger b = BigInteger.valueOf(1);
for(int i=2;i<=n;i++)
b=b.multiply(BigInteger.valueOf(i));
String s = b.toString();
int sum=0;
for(int i=0;i<s.length();i++)
sum+=(int)(s.charAt(i)-'0');
System.out.println(sum);
}
}
The limits for n is n<=1000. And it works flawlessly:
INPUT
5
60
100
1000
OUTPUT
3
288
648
10539
But the online judge is judging this as a wrong answer. Is there any problem in using the BigInteger class?
NOTE:I want the fault in the Implementation of the BigInteger class in my program, as this solution didn't exceed the time-limit but gave a wrong answer.
One of the initial conditions for your particular case is that Java 8 is used, so let's do that.
First, how to obtain the factorial for a given input number:
private static final BigInteger TWO = BigInteger.valueOf(2L);
private static BigInteger factorial(final BigInteger inputNumber)
{
BigInteger ret = BigInteger.ONE;
BigInteger b = TWO;
while (b.compareTo(inputNumber) <= 0) {
ret = ret.multiply(b);
b = b.add(BigInteger.ONE);
}
return ret;
}
Then, from that number, how to obtain the number of digits? We use base 10, we can therefore use the integer division and modulo operator:
private static int digitSum(final BigInteger someInteger)
{
int ret = 0;
BigInteger b = someInteger;
BigInteger[] modResult;
while (b.compareTo(BigInteger.ZERO) > 0) {
modResult = b.divideAndRemainter(BigInteger.TEN);
ret += modResult[1].intValueExact();
b = modResult[0];
}
return ret;
}
Now, plugging it in into a main program; you are supposed to read from a file, where inputs from that file are integers, one per line:
public final class FactDigitSum
{
// supposes that the two methods above are defined in this class
private static void printDigitSum(final BigInteger inputNumber)
{
final BigInteger factorial = factorial(inputNumber);
System.out.println(digitSum(factorial));
}
// The main program
public static void main(final String... args)
throws IOException
{
if (args.length == 0)
throw new IllegalArgumentException("No file as argument");
final Path path = Paths.get(args[0]);
try (
final Stream<String> stream = Files.lines(path);
) {
stream.map(BigInteger::new).forEach(FactDigitSum::printDigitSum);
}
}
}
Don't use the string. Calculate the value directly from the BigInteger.
This should give you the value. I'll leave I/O to you:
public class BigIntFacSum
{
private static int bigFacSum(final int n)
{
int sum = 0;
BigInteger fac = BigInteger.valueOf(2);
BigInteger num = BigInteger.valueOf(3);
for (int i = 3; i <= n; i++)
{
fac = fac.multiply(num);
num = num.add(BigInteger.ONE);
}
while (fac.compareTo(BigInteger.ZERO) > 0)
{
BigInteger[] quotRem = fac.divideAndRemainder(BigInteger.TEN);
fac = quotRem[0];
sum += quotRem[1].intValue();
}
return sum;
}
public static void main(String[] args)
{
System.out.println(bigFacSum(1000));
}
}
This is pretty fast in Java 7. It should be even faster in Java 8, as that uses Karatsuba and Burnikel-Ziegler optimizations for multiplication and division respectively (as far as I know, Java 7 doesn't).
For what it's worth: If the numbers get bigger, it is possible that the detour via string and then adding the digits in the string becomes faster. The naive way of using divideAndRemainder(BigInteger.TEN) in a loop does not work well for large numbers like 100000!. I tried this with my own implementation of BigInteger (in a different language), and the string detour was much faster for such huge nubmers. That is because the conversion to decimal is highly optimized with a divide-and-conquer algorithm and much faster than the naive loop. But only for relatively large numbers, i.e. well over 10000!. AFAIK, Java uses a similar algorithm, so the conversion to string should also be faster there, for similarly huge humbers.
I am not aware of a divide-and-conquer algorithm that counts the sum of the digits at the same time, although I don't see why it couldn't. The algorithm is not trivial though, and mine is not in Java.
But that only as an aside, in case you or anyone else may need this one day.
I have a method that is converting a decimal (double value) into a fraction and putting the numerator and denominator values into an int[] of size 2.
Testing it works out fine for most values except when I hit 0.0001. Then the return value is 1.0/1.0.
The method:
private static int[] toFractionPos(double x){
String[] parts = Double.toString(x).split("\\.");
double den = Math.pow(10, parts[1].length()); //denominator
double num = Double.parseDouble(parts[0]) * den + Double.parseDouble(parts[1]); //numerator
return reduceFraction((int)num, (int)den);
}
reduceFraction() method:
public static int[] reduceFraction(int num, int den){
int gcf = GCF(num, den); //greatest common factor
int[] rf = {num/gcf, den/gcf};
return rf;
}
Thanks!
The algorithm seems fine. However, using double is not suitable for this kind of problem, because precision decreases as the scale grows.
You should use BigDecimal and BigInteger instead. I've roughly modified your example so that it works with them, but I haven't taken care of details, i.e. parsing the String shouldn't be necessary since scale can be retrieved from a BigDecimal with a getter, you can configure different rounding modes, etc:
import java.math.BigDecimal;
import java.math.BigInteger;
public class Sample {
static int[] toFractionPos(BigDecimal x) {
String[] parts = x.toString().split("\\.");
BigDecimal den = BigDecimal.TEN.pow(parts[1].length()); // denominator
BigDecimal num = (new BigDecimal(parts[0]).multiply(den)).add(new BigDecimal(parts[1])); // numerator
return reduceFraction(num.intValue(), den.intValue());
}
static int[] reduceFraction(int num, int den) {
int gcd = BigInteger.valueOf(num).gcd(BigInteger.valueOf(den)).intValue(); // greatest
// common
// divisor
int[] rf = { num / gcd, den / gcd };
return rf;
}
public static void main(String[] args) {
int[] fraction = toFractionPos(new BigDecimal("0.0001"));
System.out.println(fraction[0] + "/" + fraction[1]); // 1/10000
}
}
Note: optimizations left as an excercise ;)
You shouldn't work with doubles as you are losing precision and this can lead to serious errors. But in the case of 1.0001 the problem is that:
Double.toString(1.0001) == "1.0E-4"
Then you try to parse "0E-4" and you get 0 instead of 1. You could do the following if you expect at most 10 decimal points:
DecimalFormat df = new DecimalFormat("0",
DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(10);
String[] parts = df.format(x).split("\\.");
How about this?
private static int[] toFractionPos(double x){
int den = (int)Math.pow(10,(int)Math.log10(Integer.MAX_VALUE));
int num = (int)(x*den);
return reduceFraction(num, den);//this came from your code
}
I think this will work,
public int[] Fraction(double n) {
BigDecimal p = BigDecimal.ONE;
BigDecimal dn = BigDecimal.valueOf(n);
while(true){
dn = dn.multiply(p);
if( dn.compareTo(new BigDecimal(dn.toBigInteger()))==0 )
break;
else
p = p.multiply(BigDecimal.TEN);
}
BigInteger num=dn.toBigInteger(), den=p.toBigInteger(), g=num.gcd(den);
num = num.divide(g);
den = den.divide(g);
int[] res = new int[2];
res[0] = num.intValue();
res[0] = den.intValue();
return res;
}
I don't have a problem anymore, However I want to understand the behaviour of some code. Initially I was generating some random numbers and somewhere in my code the Math.random was returning the same number for all iterations. I tried to create a minimal example with the following two Classes:
first Class:
public class randomTest {
public randomTest()
{ }
public double generateRandomNumber()
{
double r = Math.random();
return r;
}
public static void main(String args[])
{
randomTest t = new randomTest();
for (int i = 0; i < 10; i++)
System.out.println(t.generateRandomNumber());
}
}
The second class:
public class anotherClass {
private randomTest t = new randomTest();
public static void main(String args[])
{
for (int i = 0; i < 10; i++)
{
anotherClass c = new anotherClass();
System.out.println(c.t.generateRandomNumber());
}
}
}
I was trying to generate a minimal code example to track the reason why I am always getting the same random value for the whole 10 iterations. In this minimal example the results are correct and random, However In my real situation The output of the second class is the same for the whole ten iterations.
At last i was able to solve the problem by changing the method I am calling into a static method. I still don't understand how did this solve my problem, and where the original problem was.
Old Nonworking code:
...
public ImagePlus createAnImage()
{
drawBackground(c.ip);
width = ip.getWidth();
height =ip.getHeight();
createCircles(requiredCircles); // this is not creating random numbers
ArrayList<Circle> list = circlesList;
drawBoundaries(list, ip, percentage);
background.setProcessor(ip);
return background;
}
...
New Code:
...
public static ImagePlus createAnImage()
{
createCircles c = new createCircles();
c.drawBackground(c.ip);
c.width = c.ip.getWidth();
c.height =c.ip.getHeight();
c.createCircles(c.requiredCircles); // this is creating random numbers
ArrayList<Circle> list = c.circlesList;
c.drawBoundaries(list, c.ip, c.percentage);
c.background.setProcessor(c.ip);
return c.background;
}
...
In both cases I was already creating an instance of createCircles class from another class as follows:
...
private ImagePlus createRandomImage(int radius, int numberOfCircles, double minPercentage, double maxPercentage, int minBackground, int maxBackground)
{
// create the image using class createCircles
createCircles c = new createCircles();
c.setParameters(radius, radius, minBackground, maxBackground, numberOfCircles, imageWidth, imageHeight, minPercentage, maxPercentage);
ImagePlus imp = c.createAnImage(); // calling the static method works
return imp;
}
Although my problem is solved, I still need to understand the reason behind this. I suppose a better understanding of static vs. non-static methods might explain it. Anyone has a clue?
Best Regards,
M. Tleis
Do not use Math.random (it produces doubles, not integers)
use the Random class to generate random integers between 0 and N.
To generate a series of random numbers as a unit, you need to use a single Random object - do not create a new Random object for each new random number.
import java.util.Random;
/** Generate 10 random integers in the range 0..99. */
public final class RandomInteger {
public static final void main(String... aArgs){
log("Generating 10 random integers in range 0..99.");
//note a single Random object is reused here
Random randomGenerator = new Random();
for (int idx = 1; idx <= 10; ++idx){
int randomInt = randomGenerator.nextInt(100);
log("Generated : " + randomInt);
}
log("Done.");
}
private static void log(String aMessage){
System.out.println(aMessage);
}
}