Use of integers and doubles give different answers when they shouldn't - java

I'm solving a Project Euler Problem 14 using java. I am NOT asking for help solving the problem. I have already solved it, but I ran into something I can't figure out.
The problem is like this:
The following iterative sequence is defined for the set of positive
integers:
n = n/2, if n is even
n = 3n + 1, if n is odd
Using the rule above and starting with 13, we generate the following
sequence:
13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1. Here, the length of the chain is 10 numbers.
Find the starting number below 1,000,000 that produces the longest chain.
So I wrote this code:
public class Euler014 {
public static void main(String[] args){
int maxChainCount = 0;
int answer = 0;
int n;
int chainCount = 1;
for(int i = 0; i < 1000000; i++){
n = i;
while(n > 1){
if(n%2 == 0){ //check if even
n /= 2;
}else{ //else: odd
n = 3*n + 1;
}
chainCount++;
}
if(chainCount > maxChainCount){ //check if it's the longest chain so far
maxChainCount = chainCount;
answer = i;
}
chainCount = 1;
}
System.out.println("\n\nLongest chain: i = " + answer);
}
}
This gives me the answer 910107, which is wrong.
HOWEVER, if i change the type of my n variable to double n it runs and gives me the answer 837799, which is right!
This really confuses me, as I can't see what the difference would be at all. I understand that if we use int and do divisions we can end up rounding numbers when we don't intend to. But in this case, we always check to see if the n is divisble by 2, BEFORE dividing by 2. So I thought that it would be totally safe to use integers. What am I not seeing?
This is the code in its entirety, copy, paste and run it if you'd like to see for yourself. It runs in a couple of seconds despite much iteration. =)

Your problem is overflow. If you change int n to long n, you'll get the right answer.
Remember: The numbers in the sequence can be really big. So big they overflow int's range. But not (in this case) double's, or long's.
At one point in the chain, n is 827,370,449 and you follow the 3n + 1 branch. That value wants to be 2,482,111,348, but it overflows the capacity of int (which is 2,147,483,647 in the positive realm) and takes you to -1,812,855,948. And things go south from there. :-)
So your theory that you'd be fine with integer (I should say integral) numbers is correct. But they have to have the capacity for the task.

Related

Divide and conquer sum of array iterative

Is it possible to get the sum of an array using divide and conquer? I've tried it, but I always miss some numbers, or I calculate a number twice.
int[] arr = new int[]{1,2,3,4,5};
public int sum(int[] arr) {
int begin = 0;
int end = array.length - 1;
int counter = 0;
while (begin <= end) {
int mid = (begin + end) / 2;
counter += arr[end] + arr[mid];
end = mid - 1;
}
return counter;
}
Of course, Diveide-and-conquer computation of the array's sum is possible. But I cannot see a UseCase for it? You're still computing at least the same amount of sums, you're still running into issues if the sum of arrayis greater than Integer.MAX_VALUE, ...
There is also no performance benefit like Codor showed in his answer to a related question.
Starting with Java 8 you can compute the sum in 1 line using streams.
int sum = Arrays.stream(array).sum();
The main flaw with your above code is the fact that you're only summing up index mid(2) and end(4). After that you skip to the lower bracket (index mid = 0 and end = 2). So you're missing index 3. This problem will become even more prevelant with larger arrays because you're skipping even more indices after the while's first iteration.
A quick Google search brought up this nice-looking talk about the general Divide-and-Conquer principle using a mechanism called Recursion. Maybe it can guide you to a working solution.

foobar challenge: Minion's bored game

Edit: It appears people are confusing this question for another. Both questions are about the same Foobar challenge. The other question asked for an approach better than the exponential time or omega(answer) brute force search, since a brute force search took too long. The answers there suggested using dynamic programming, which is a good idea that is much faster than a brute force search or backtracking, although not the best possible. This question starts with dynamic programming, which works on 4 out of 5 tests, but which seems to get the wrong answer for the 5th and perhaps largest test case. It doesn't take too long. It completes but gets the wrong answer. The answers to the other question do not help with this question, nor does the answer to this question help with that one, so they are not duplicates. They are about different aspects of the same task.
I am working on a Foobar Challenge, trying to determine the number of possible "Winning" roll combinations an individual could make using a 3-sided die. The simulated user will roll t times on a 1-dimensional "game-board" that is n spaces wide. The 3 sided die has 3 possible values: left (-1), stay (0), right (1). User starts out at location '0' on the board. If you are at 0 and you roll a -1 (left) then the game is invalid. If you are on the final square the only valid roll is 0 (stay). The objective is to determine the total amount of roll combinations a user could make that ends up with their marker being on the last square. (READ THE FULL CHALLENGE DESCRIPTION BELOW).
I have a semi-functioning solution to this challenge; however, when I submit it for review it fails 1 out of 5 test scenarios; problem is, Foobar doesn't disclose what the exact scenario was that failed, it simply says 'Test 5 failed!'. Would anybody be able to look at my Java code (below) and see what I am missing?
Here is my code:
public static int answer(int t, int n) {
if ((n - t) > 1) {
return 0;
}
if (n == 2) {
return t * 1;
}
if (t == n) {
return n;
}
// Use dynamic programming:
int lst[] = new int[n]; // lst[k] holds the # valid paths to position k using i-1 steps
int lst2[] = new int[n]; // put # valid paths to position k using i steps into lst2[k]
int total = 0;
lst[0] = 1;
lst[1] = 1;
int max = 1;
for (int i = 1; i < t; i++) {
lst2 = new int[n];
if (max < (n - 1)) {
max++;
}
for (int j = 0; j < n && j < (max + 1); j++) {
if (j == 0) {
lst2[j] = lst[j] + lst[j + 1];
} else if (j == max) {
if (j == (n - 1)) {
total += lst[j - 1];
} else {
lst2[j] = lst[j - 1];
}
} else {
lst2[j] = lst[j - 1] + lst[j] + lst[j + 1];
}
}
lst = lst2;
}
return total % 123454321;
}
Original Challenge Text
There you have it. Yet another pointless "bored" game created by the bored minions of Professor Boolean.
The game is a single player game, played on a board with n squares in a horizontal row. The minion places a token on the left-most square and rolls a special three-sided die.
If the die rolls a "Left", the minion moves the token to a square one space to the left of where it is currently. If there is no square to the left, the game is invalid, and you start again.
If the die rolls a "Stay", the token stays where it is.
If the die rolls a "Right", the minion moves the token to a square, one space to the right of where it is currently. If there is no square to the right, the game is invalid and you start again.
The aim is to roll the dice exactly t times, and be at the rightmost square on the last roll. If you land on the rightmost square before t rolls are done then the only valid dice roll is to roll a "Stay". If you roll anything else, the game is invalid (i.e., you cannot move left or right from the rightmost square).
To make it more interesting, the minions have leaderboards (one for each n,t pair) where each minion submits the game he just played: the sequence of dice rolls. If some minion has already submitted the exact same sequence, they cannot submit a new entry, so the entries in the leader-board correspond to unique games playable.
Since the minions refresh the leaderboards frequently on their mobile devices, as an infiltrating hacker, you are interested in knowing the maximum possible size a leaderboard can have.
Write a function answer(t, n), which given the number of dice rolls t, and the number of squares in the board n, returns the possible number of unique games modulo 123454321. i.e. if the total number is S, then return the remainder upon dividing S by 123454321, the remainder should be an integer between 0 and 123454320 (inclusive).
n and t will be positive integers, no more than 1000. n will be at least 2.
Languages
To provide a Python solution, edit solution.py To provide a Java solution, edit solution.java
Test cases
Inputs: (int) t = 1 (int) n = 2 Output: (int) 1
Inputs: (int) t = 3 (int) n = 2 Output: (int) 3
The counts grow exponentially in t. My guess is that the error is that you are overflowing the integer range. Reduce intermediate results mod m, or use a java.math.BigInteger.
Ok to make it simple yes there is a problem with int overflow. However you don't need to use a larger container ex BigInteger. All you need to store int the second array is the remainder ex lst2[j] = (lst[j - 1] + lst[j] + lst[j + 1]) % 123454321;. By doing this your value will never exceed 123454321 which will easily fit within an integer. then after every iteration of i use total %= 123454321; then you just need to return total. Since we are just adding paths moding the intermediate result just reduces it back to a manageable number.

product of the numbers in list in java

My task here is to find the minimal positive integer number say 'A' so that the product of digits of 'A' is exactly equal to N.
example: lets say my N = 32
so my A would be 48 coz the divisors of 32 would be 1,2,4,8,16,32 and the minimum numbers that would make 32 is 4 and 8. so output is 48.
what i did is first read N, then found the divisors and stored them in a list. and used
if(l.get(i)*l.get(i+1)==N) {
sysout.print(l.get(i));
sysout.print(l.get(i+1));
but im not able to make the numbers as minimum. and also i need to print as -1 if no match is found.
for that i did:
if (l.get(i)*l.get(i+1)!=N) {
System.out.print(-1);
break;
}
but it is printing -1 initially only and breaking off. now im stuck here. please find my code below:
my code:
int N=1;
Scanner in = new Scanner(System.in);
List<Integer> l = new ArrayList<Integer>();
System.out.println("Enter N: ");
if (N>=0 && N<=Math.pow(10, 9)) {
N = in.nextInt();
}
for (int i=1; i<=N;i++) {
if (N%i==0) {
l.add(i);
}
}
System.out.println(l);
for (int i=0; i<l.size()-1;i++) {
if (l.get(i)*l.get(i+1)==N) {
System.out.print(l.get(i));
System.out.print(l.get(i+1));
}
}
in.close();
kindly help. thanks.
You're on the right track with finding the divisors on N. I'm not going to code it for you(you'll learn more by doing) but here's what you do: The divisors will be sorted already so loop the arraylist adding first to last and finding the min.
So for 1,2,4,8,16,32: Find 1+32, 2+16, 4+8; And then fin the max among these.
This is to get you started:
int first = 0;
int last = l.size()-1;
while(first<last){
//Find min using Math.min;
++first;
--last;
}
Happy Coding!
Could not resist. Below is a quick way to do what you want. Tested it here
(https://ideone.com/E0f4X9):
public class Test {
static ArrayList<Integer> nums = new ArrayList<>();
public static void main(String[] args){
int N =32;
findDivisors(N);
int first = 0, a = 0, b = 0;
int last = nums.size()-1;
int results = Integer.MAX_VALUE;
while(first < last){
int sum = nums.get(first) + nums.get(last);
results = Math.min(sum,results);
a = nums.get(first);
b = nums.get(last);
first++;
last--;
}
System.out.println(a+" "+b);
}
private static void findDivisors(int n){
for(int i=1; i<=n; i++){
if(n%i == 0){
nums.add(i);
}
}
}
}
Obviously if N<10 then A=N.
Otherwise A has to consist of more than one digit. Every digit of A is a divisor of N. The more significant digits of A always have to be less or equal than the lesser significant digits. Otherwise the order of digits could be changed to produce a smaller number.
For example A could not be 523 because the digits could be rearranged into 235 which is a smaller number. In this example we have 2 < 3 < 5.
Observation #1: when looking at A the smallest digits are at the front, the digits get higher towards the end.
Observation #2, A can never contain two digits a and b if the product of a and b is also a digit. For example, there can never be a 2 and a 3, there would have to be a 6 instead. There could never be three 2s, it would have to be an 8 instead.
This suggests that when building A we should start with the highest possible divisors of N (because a 9 is always better than two 3s, and so on). Then we should put that digit at the end of A.
So, while N > 10, find the highest divisor x of N that is a single digit (2<=x<=9). Add this value x to the end of A. Divide N by x and proceed with the loop.
Example:
N=126, A=?
Highest possible divisor x that is less or equal to 9 is 9. So 9 is going to be the last digit of A.
Divide N by 9 and repeat the process. N=126/9=14.
Now N=14, A=?9
Highest possible divisor x that is less or equal to 9 is 7. We have found the second to last digit of A.
Divide N by 7 and repeat the process. N=14/7=2.
Now N=2, A=?79
N<10. So 2 is the first digit of A.
The solution is A=279

Find missing term in arithmetic progression -

So I'm working on this programming challenge online where I'm supposed to write a program that finds the missing term in an arithmetic progression. I solved the problem in two ways: one that used summing all the given terms of the progression and then subtracting that from the sum of the actual progression. My other solution was based on finding the difference of the progression, and then using that difference in a for loop to find the missing term. While my first solution successfully passes all test cases, my second solution fails two out of the 7 test cases. The challenge doesn't allow anyone to see their test cases so I had no idea what was wrong. Can anyone think of cases where my second solution fails to find the missing term of an arithmetic progression? Code for my second solution is below.
import java.io.*;
import java.util.Vector;
public class Solution {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int num = Integer.parseInt(br.readLine());
String[] numbers = br.readLine().split(" ");
Vector<Integer> ap = new Vector<Integer>();
for (String str: numbers){
ap.add(Integer.parseInt(str));
}
int first = ap.get(0);
int last = ap.get(ap.size()-1);
int incr = (last-first)/num;
for(int i = first; i<=last; i+= incr){
if(!ap.contains(i)){
System.out.println(i);
break;
}
}
}
}
Input Format The first line contains an Integer N, which is the number of terms which will be provided as input. This is followed by N consecutive Integers, with a space between each pair of integers. All of these are on one line, and they are in AP (other than the point where an integer is missing).
public class MissingAp
{
public static void main(String args[]){
int arr[] ={10,8,4,2,0,-2,-4,-6,-8,-10,-12};
int difference[]=new int[arr.length-1];
int missingTerm;
for(int i=1;i<arr.length;i++){
difference[i-1] = arr[i]-arr[i-1];
}
for(int j =0;j<arr.length-1;j++){
if(difference[j]!=difference[j+1]){
missingTerm = arr[j]+difference[j+1];
System.out.println("The missing term is: " + missingTerm );
break;
}}}}
This program will help you find missing term of an AP.
Wouldn't this fail if the sequence is decreasing instead of increasing?
If I had the numbers 10, 8, 4, 2, 0, the missing value would be 6.
You find increment of -10/5 = -2 properly.
But then the loop you start from i = 10, decrease by 2... as long asi <= 0. Well immediately i is > 0, so it'd exit the loop before decreasing at all. < only works if increasing.
So it's the i<=last statement that I think is the problem.
So you'd need seem kind of way to adjust the i<=last; statement based upon whether it is a positive or negative increment. I'm thinking it would have to do with absolute value and\or Math.signum, or including separate code section based upon a negative increment (not the fastest way, but reasonable). But I've never done much in Java, and you asked for how it failed. So hopefully there's your answer :-)
Sort the array to ensure that this works for any case.
Arrays.sort(input_array)
A JavaScript based solution for the same:
This has 2 cases:
CASE 1:
The array passed in has just one missing term, and the first and last
terms are not the missing ones. It definitely has a missing term.
In this case, we just need the array and use the basic school formula
sum of n terms = n/2 * (first + last)
function getMissingTerm(terms, n) {
var expectedSum = ((terms.length + 1)/2) * (terms[0] + terms[terms.length - 1]),
actualSum = 0;
for (var i = 0; i < terms.length; ++i) {
actualSum += parseInt(terms[i], 10);
}
return expectedSum - actualSum;
}
CASE 2:
The array passed does not have a missing term in itself
meaning the missing term is either the first or last term
In this case one must pass the length of the terms, n, which is greater than array length
function getMissingTerm(terms, n) {
var smallestDifference = Math.abs(terms[1] - terms[0]),
missingTerm = null;
for (var i = 2, diff; i < terms.length; ++i) {
diff = Math.abs(terms[i] - terms[i - 1]);
if (diff !== smallestDifference) {
missingTerm = diff < smallestDifference ? i : i + 1;
}
}
return (n && terms.length < n) ?
[terms[0] - smallestDifference, terms[n-2] + smallestDifference] : // return possible 2 terms, at the start and end of array
terms[0] + (missingTerm - 1) * smallestDifference; // return the missing term
}

I'm trying to find the sum of primes below 2 million in Java [duplicate]

This question already has answers here:
Project Euler #10 Java solution not working
(6 answers)
Closed 9 years ago.
I'm trying to find the sum of primes below millions. My code works when I try to find the sum of primes below hundred thousands but when I go large numbers it doesn't work. So I need some help to get this work for big numbers...
import java.util.Scanner;
public class sumPrime {
public static void main (String args []){
long n = 2000000; int i; int j;int sum =0;
for (i=2; i <n; i++){
for (j=2; j<i; j++){
if (i%j==0){
break;
}
}
if (i==j){
sum +=i;
}
}
System.out.print(sum);
}
}
Your code could be improved by making the inner loop stop earlier. If a number N is not prime, then it must have at least one factor (apart from 1) that is less or equal to sqrt(N). In this case, this simple change should make the program roughly 1000 times faster.
For a simple and (more) efficient algorithm, read up on the Sieve of Eratosthenes.
Bug - your sum needs to be a long. An int will probably overflow.
Note that the classic formulation of Sieve of Eratosthenes needs a large array of booleans (or a bitmap) whose size depends on the largest prime candidate you are interested in. In this case that means a 2Mbyte array (or smaller if you use a bitmap) ... which is too small to worry about. Also, you can reduce the memory usage by sieving in stages, though it makes the code more complicated.
Rather than trying to divide by all the numbers below i you could potentially keep the found prime numbers in a list and try to divide by those prime numbers (since any non prime number will be divisible by a prime number less than that).
public static long sumPrime2() {
List<Long> primes = new ArrayList<>();
primes.add(2L);
primes.add(3L);
long primeSum = 5;
for (long primeCandidate = 5; primeCandidate < 2000000; primeCandidate = primeCandidate + 2) {
boolean isCandidatePrime = true;
double sqrt = Math.sqrt(primeCandidate);
for (int i = 0; i < primes.size(); i++) {
Long prime = primes.get(i);
if (primeCandidate % prime == 0) {
isCandidatePrime = false;
break;
}
if (prime > sqrt) {
break;
}
}
if (isCandidatePrime) {
primes.add(primeCandidate);
primeSum += primeCandidate;
}
System.out.println(primeCandidate);
}
System.out.println(primes.size());
return primeSum;
}
This gave the answer in 8 seconds
I suspect integer overflow in i, j, sum - try making them all longs. In the sample code you shouldn't be getting overflows as Java ints are meant to be 32 bit but at some stage you certainly will.
As already mentioned - i only needs to iterate to the square root of n. So I would replace this line:
for (i=2; i <n; i++){
With:
long limit=sqrt(n);
for (i=2; i <limit; i++){
Note that calculating the square root outside the program loops will also speed things up a bit.
Also the sieve algorithm would be faster but requires Java to create an array containing n elements and at some stage that is going to fail with insufficient memory.
The best algorithm for this program uses the Sieve of Eratosthenes:
function sumPrimes(n)
sum, sieve := 0, makeArray(2..n, True)
for p from 2 to n
if sieve[p]
sum := sum + p
for i from p*p to n step p
sieve[i] := False
return sum
Then sumPrimes(2000000) returns the sum of the primes less than two million, in about a second. I'll leave it to you to translate to Java, with an appropriate data type for the sum. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.

Categories

Resources