Project Euler problem 8 involves finding the largest product of 13 consecutive digits in a 1000-digit number. I've tried to solve this problem with the code below, but the results I am getting are too small by a factor of about 10. What have I done wrong?
import java.util.Scanner;
import java.util.*;
public class eight {
public static void main(String[] args) {
String number="7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
String input = "782";
int value = 782;
List<Integer> x = new ArrayList<Integer>();
for (char ch : number.toCharArray()){
int element_add=Character.getNumericValue(ch);
x.add(element_add);
}
int check_count=0;
int multiply_value=0;
int multiply_value_max=0;
while(check_count<986){
multiply_value=(x.get(check_count))*(x.get(check_count+1))*(x.get(check_count+2))*(x.get(check_count+3))*(x.get(check_count+4))*(x.get(check_count+5))*(x.get(check_count+6))*(x.get(check_count+7))*(x.get(check_count+8))*(x.get(check_count+9))*(x.get(check_count+10))*(x.get(check_count+11))*(x.get(check_count+12));
if(multiply_value>multiply_value_max){
multiply_value_max=multiply_value;
}
check_count++;
}
System.out.println(multiply_value_max);
}
}
The problem you have is that the upper bound for the answer can be greater than maximum value of int. Therefore, you need to use the BigInteger class, or at the very least long, to store the result. To ensure that the operations are carried out with sufficient precision, you want to store the individual digits in the same precision or convert them to the precision as you multiply them.
You can also save yourself some typing and boilerplate errors by handling the consecutive multiplication with a for loop.
Related
I tried to calculate a series of the N first fibonacci numbers using Binets Formula.
Every result i get is correct until F47 where the result is NEGATIVE.
This is my result : -1323752223
And heres the expected result : 2971215073
I really think the problem occures during the double to int conversion
Source Code:
import java.lang.Math;
class fibonacci{
public static int NthFibonacci(int n){
double fi = 1.61803398875;
int fb = (int)Math.round((Math.pow(fi,n) - Math.pow(1-fi,n))/Math.sqrt(5));
return fb;
}
public static void FibonacciSeries(Integer n){
for(int i = 0; i < n; i++){
System.out.println(NthFibonacci(i) + " ");
}
}
public static void main(String[] args) {
FibonacciSeries(50);
}
}
The real explanation for the behavior of the version in your question giving a negative number is a bit subtle.
At F47, this expression
(Math.pow(fi, n) - Math.pow(1 - fi, n)) / Math.sqrt(5)
will give you 2.971215073009069E9 ... which is close to the desired 2971215073.
The problem arises when you call Math.round(2.971215073009069E9). This returns a long - 2971215073L. But then you cast the result of the round call to an int, and it all goes pear-shaped.
Casting a long to an int will just lop off the top 32 bits ... and that results in a meaningless number.
If we modify fibonacci to return a long instead of an int, we get correct results up to F55. F56 and F57 are off by 1. F58 is off by 2.
What is happening now is that we are running into the problem that double (64-bit IEEE floating point) has only about 13.5 decimal digits of precision. The rounding error incurred in the computation of the intermediate floating point value for F56 larger that 0.5 ... so the rounded value is then incorrect.
The computed fibonacci numbers continue to get increasingly inaccurate until you get to F93, where the (modified) fibonacci method returns Long.MAX_VALUE.
To get correct values for very large Fibonacci numbers:
we need to use BigInteger to represent the numbers,
we need to do the computations using BigDecimal with sufficient precision, and (maybe)
we need to use a more accurate value for phi.
Or we need to use the recurrence relationship to compute the numbers.
The 2 take-aways from all of this are:
casting a long to an int is a lossy conversion, and
floating point arithmetic is inexact and ... tricky.
I think that the problem does not have something to do with the double conversion.
int can store numbers that can be represented by 32 bits. This means the highest number integer can represents is 2.147.483.647.
The F47 is breaking this limit and results in an bit-overflow, so it starts at -2.147.483.68 and adds the rest of your 2971215073 - 2147483647 to it. -1323752223 is the outcome.
Use a long (64bit) instead of an int and you should be good :)
2971215073 is too big to be represented as an int at all. The maximum value of an int -- Integer.MAX_VALUE -- is 2^31 - 1, or 2147483647.
Ok so i found a decent fix.
I used a Geometrical version of Binets rule which you can find here : Binets Geometrical Rule
I also used long instead of int so now I can accurately calculate up to F70. F71 is wrong by a digit and after that it just builds up.
New Source Code :
import java.lang.Math;
class fibonacci{
public static long NthFibonacci(int n){
double a = (1/Math.sqrt(5))*Math.pow(2, n);
double radians1 = Math.toRadians(36.0);
double radians2 = Math.toRadians(108.0);
double b = Math.pow(Math.cos(radians1), n) - Math.pow(Math.cos(radians2), n);
long fb = (long) Math.round(a*b);
return fb;
}
public static void FibonacciSeries(int n){
for(int i = 0; i < n; i++){
System.out.println( i + " : " + NthFibonacci(i));
}
}
public static void main(String[] args) {
FibonacciSeries(100);
}
}
I am trying to solve this problem on hackerrank and it took me a while to get to the trick.
The trick lies in property of xor and the number of times a number appears in a subset of array where a subset is contiguous one (kindly note).
So if we have 1,2,3 the subsets will be:
1
1,2
1,2,3
2
2,3
3
The number of times a value at index i appears in these subsets is (n-i)*(i+1) as it can be seen that 1 appears (3-0)*(0+1) = 3 times. n is the length of the array.
Second trick is XOR of a number is 0 with itself if we take that number even number of times and if it appears odd number of times the answer is the number itself, also the important thing to note is XOR operation is associative.
The problem asks us to xor the subsets and then take XOR of each resultant value.
So rather than brute force approach, I counted the number of times each number appears in array and checked out whether it occurs even number of times or odd number of times but 8 testcases passed and 4 failed. The test case are too long to debug or dry run.
My question is why 4 testcase failed. Here is the Java code.
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class J {
static int []arr=new int[100000];
static int an;
public static void main(String[] args)throws IOException {
/* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
int t,i,j,n;String []s;
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
t=Integer.parseInt(br.readLine());
int []ans=new int[t];
for(i=0;i<t;++i)
{
n = Integer.parseInt(br.readLine());
s=br.readLine().split(" ");
j=0; an=0;
for(String str:s)
arr[j++]=Integer.parseInt(str);
for(j=0;j<n;++j)
{
if(((j+1)*(n-j))%2==1)
an=an^arr[j];
}
ans[i]=an;
}
for(i=0;i<t;++i)
System.out.println(ans[i]);
}
}
The reason is overflow in
(j+1)*(n-j)
The product may be ~10^10 cause the total size of array is up to 10^5.
So you need to calculate this product using long.
I tested your code with this dummy change:
long a = j + 1;
long b = (n - j);
if((a*b)%2==1) {
an=an^arr[j];
}
And program passed all tests successfully.
This is my code. It shows an error when I create an array of BigInteger and try to assign a value.
package test;
import java.math.*;
import java.lang.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
BigInteger[] coef = new BigInteger[78];
int a=24;
coef[a]=676557656534345345654645654654645645645645665656567; // Error comes here why
System.out.println(coef[a]);
}
}
Java have static types and the auto boxing is only enabled for the wrappers of primitive types, like int to Integer, but not for BigInteger. You will have to do
new BigInteger("676557656534345345654645654654645645645645665656567")
explicitly.
First of all number grater then 2147483647 will not be allowed as input because int range is -2147483648 : 2147483647. if your your output is grater than this number it will automatically reverse and to its lowest value i.e -2147483648.
For bit number to operate with BigInteger take the number as String.
And as your problem I would suggest to use
coef[a]=new BigInteger("676557656534345345654645654654645645645645665656567");
As it gives you all relevant methods from java.lang.Math you can perform arithmetic operation by passing string in it..check this document
I have made Fabonacci series which give a huge output when a big number is passed to it....
Have a look at Fabonacci series on my GitHub
Hope it helps you!!
KEEP IN MIND ALWAYS
All numbers greater then 2147483647 will not be allowed as input because int range is -2147483648 to 2147483647 (Never forget it).
If just in case your output is greater than the limit it will reverse and to its lowest value i.e -2147483648.
I recommend that you use:
coef[a]=new BigInteger("324576565343453456546456546546456456456455643671");
All important functions are in java.lang.Math class and you can perform arithmetic operations by passing a string to it.
public static void main(String[] args) {
BigInteger[] coef = new BigInteger[78];
int a = 24;
coef[a] = new BigInteger("676557656534345345654645654654645645645645665656567");
System.out.println(coef[a]);
}
I am doing a question for college on cryptography. Part of my program is that I want to get the power x such that (2744^x) % 24852977 = 8414508. I have a loop that increases a double by 0.001. My question is this: instead of my loop increasing by 0.001 each time it shows a number a lot longer in decimal places. Is this to do with the long MIN/MAX value and if so how would i be able to fix this, or can anyone explain were I'm going wrong? Here is a sample of my increment. How do get the cut off point of 4 decimal places.
10.276999999989387
10.277099999989387
10.277199999989387
10.277299999989387
10.277399999989386
10.277499999989386
10.277599999989386
10.277699999989386
10.277799999989385
import java.lang.*;
public class crypt {
public static void main(String args[])
{
long p =24852977;//variables
long g = 2744;
long sum = 8414508;
long c1 = 15268076;
long c2 = 743675;
for(double i=0; i<=p; i=i+0.0001)//loop for increasing the power in next part of the program
{
long num=(long)(Math.pow((long)g, i));//number = g to the power of i
System.out.println(i);// just to check
if(num % p == sum)//my equation
{
System.out.println(i);//print the power that satisfy's this
}
}
}
}
Remember that the internal representation of numbers is binary. So, there is not necessarily an exact binary representation for every decimal number. That is, there is no exact representation of your 0.0001 increment and a rounding error is expected.
I am randomly generating numbers using java.util.Random. But, I can not keep the length of the numbers fixed. Can you help me please?
To fix the length of a randomly generated number, generally you'll want to fix the random number generation to a range. For instance, if you'd like to generate a 6 digit long random number, you'll want numbers from 100,000 to 999,999. You can achieve this by using the following formula.
Random r = new Random();
int randomNum = r.nextInt((max - min) + 1) + min;
Where max is the maximum number, such as 999999, and min is your minimum number, such as 100000.
EDIT:
Based on your comment, I see that you're trying to generate a 15-digit number containing only 1-5 inclusive. Here is a simple way to do this:
import java.util.Random;
StringBuilder s = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 15; i++) {
s.append(r.nextInt(5) + 1);
}
System.out.println("The random number is: " + s.toString());
As noted by #MichaelT, a 15 digit number will not fit in an integer. If you need to perform an operation on it, you should store it in a long.
long randomLong = Long.valueOf(s.toString()).longValue();
Rather than thinking of generating an integer, think in terms of generating a String of 15 digits, each in the required range.
You can use nextInt(int) to pick each digit.
The first thing to consider is that an int cannot hold 15 digits. It just can't. It can only go up to 232 -1, which is 9 digits long. A long can hold up to 19 digits - but if one wants to solve for the general case, it is necessary to use the BigInteger package instead.
Remember that BigInteger is an immutable object (like String) and thus you must assign the value back when looping.
package com.michaelt.so.random15;
import java.math.BigInteger;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random r = new Random();
BigInteger result = BigInteger.ZERO;
for(int i = 0; i < 15; i++) {
result = result.multiply(BigInteger.TEN)
.add(BigInteger.valueOf(r.nextInt(5)+1));
}
System.out.println(result.toString());
}
}
It starts out with the value ZERO, and loops through for 15 times, each time first multiplying the value by 10 (another BigInteger preallocated value) and then adds the new value into the 1's position. It does this 15 times.
When done, one can get its value as a string or long or other format - or continue to use it as a BigDecimal (necessary if you should ever decide you want a 20 digit long value).
Runs of the above code produce output such as:
313455131111333
245114532433152
531153533113523
If you're ok using libraries:
RandomStringUtils.random(15, "12345")
would give you Strings like: 124444211351355 of length 15
I just happened to write a post about that (shameless self-advertising link: http://united-coders.com/nico-heid/generating-random-numbers-strings-java/)