I am doing a maths challenge for project euler and i have come across a strange problem when running the program. The result should be the sum of all the odd numbers up to 10,000,000 but i get a negative number, what am i doing wrong?
package program;
import java.util.*;
public class MainClass {
/**
* #param args
*/
public static void main(String[] args) {
int total = 0;
for (int counter = 1; counter < 10000000; counter++) {
if (!((counter % 2) == 0)) {
total+=counter;
}
}
System.out.println(total);
}
}
Use a long instead of an int. You're getting a negative number due to integer overflow.
The int variable can't hold the total because the total is too big. At some point in the loop, you're getting an integer overflow and it's "rolling over" to a negative number:
You need a long.
A matter of style and efficiency, I'd change the code to iterate by 2 so that you don't need the test for oddness:
public static void main(String[] args) {
long total = 0;
for (int counter = 1; counter < 10000000; counter += 2) { // iterate by 2
total += counter;
}
System.out.println(total);
}
You should use long total = 0; instead of int total = 0; int in java is 4 bytes and ranges from -2,147,483,648 to 2,147,483,647.
so 2,147,483,647 + 1 = -2,147,483,648
The total for this loop comes out to be 25,000,000,000,000 which can be accommodated by long
Just to throw in the more clever solution to this problem (MATH! yay).
You can solve this much easier, you just need to know that the sum of odd numbers from 1..2n-1 is equal to the square of n. It's pretty easy to prove this with induction for those who want to try.
Anyways this means that the sum from 1..X is equal to: ((X + 1) / 2)**2
Related
Background:
I'm working on Project Euler problem #2 and I have a class built to solve the problem. For those who haven't done this before, this is the problem:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... .
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
The problem:
I have the program built to solve the problem given, but when I run it, I get the value -1833689714. This should not be the value returned, as I sum only positive numbers and no multiplications are performed that I know of. How do I fix this?
My code
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
int answer = resultsSum(fibonacci(4000000));
System.out.println(answer);
}
public static int resultsSum(ArrayList<Integer> resultList){
int total = 0;
for(Integer r : resultList){
total += r.intValue();
}
return total;
}
public static ArrayList<Integer> fibonacci(int n){
ArrayList fibEvens = new ArrayList<Integer>();
int a = 1;
int b = 2;
fibEvens.add(b);
for(int i = 1; i < (n - 1); i++) {
int tempVar = a;
a = b;
b += tempVar;
if(b % 2 == 0){
fibEvens.add(b);
}
}
return fibEvens;
}
}
https://projecteuler.net/problem=2
The reason you're getting a negative result is that the the terms of the Fibonacci sequence above the 88th term are in excess of the maximum positive value of the Long data type in java, which is 9,223,372,036,854,775,80.
When you attempt to increment the long data type beyond it's max value by one it wraps around to the minimum value (-9,223,372,036,854,775,80). At the point the Fibonacci terms exceed the max value, you're doing this many times over.
Additionally, the problem you've posted indicates that you should be stopping when the value of the number derived from the sequence is greater than 4 million, not trying to add the even values of the first 4 million values (which is huge).
It looks like your code is attempting to get to the 4-millionth Fibonacci number, which is quite different than the terms in the Fibonacci sequence whose values do not exceed four million.
Because
int data type stores number from -2^31 to 2^31 - 1
Integer data type stores number from -2^63 to 2^63 - 1
Try with BigInteger
public static BigInteger fibonacci(int n) {
BigInteger[] f = new BigInteger[n + 1];
f[0] = BigInteger.ZERO;
if (n > 0) {
f[1] = BigInteger.ONE;
}
for (int i = 2; i < f.length; i++) {
f[i] = f[i - 1].add(f[i - 2]);
}
return f[n];
}
But the 4 million Fibonacci value very long. See more 300th, 500th
Here is my code. I tried to Convert the binary to a Char array, then multiply each char in the array by 2 to the power of its corresponding number in the array, then sum up all the values of the char array into a double. New to programming so a bit confused. My input Binary is txfBinaryInput, and my output label is lblDisplay.
private void btnProcessActionPerformed(java.awt.event.ActionEvent evt)
{
if (txfBinaryInput.getText().equals(""))
{
lblDisplay.setText("ERROR: NO INPUT");
} else
{
int n = 0;
int[] binaryValueStorage = new int[100];
double[] decimalValueStorage = new double[100];
String binaryInput = txfBinaryInput.getText();
int binaryNumber = binaryInput.length();
char[] binaryDigits = binaryInput.toCharArray();
for (int i = 0; i >= binaryNumber; i++)
{
binaryValueStorage[n] = binaryDigits[n];
decimalValueStorage[n] = binaryValueStorage[n] * (Math.pow(2, n));
n++;
}
double sum = 0;
for (double a : decimalValueStorage)
{
sum += a;
}
lblDisplay.setText("The Deciaml Value Is " + sum);
}
}
Beware: in your for loop condition, you have i >= binaryNumber instead of i < binaryNumber, therefore your program will never enter the loop!
And on a side note, why are you using two variables, i and n, for the same purpose (incrementing and accessing the array)?
Edit: another issue:
In binary numbers, lower order bits are to the right, but in arrays, indices are from left to right!!
So you want your rightmost digit to be multiplied by 2^0, the next one right to its left by 2^1, and so on.
But in your code, what is happening is the opposite: it is the leftmost digit (your digit at index 0) that is being multiplied by 2^0!
To fix, you can either:
1) reverse your binaryDigits array before starting to convert, and keep the rest of your code untouched
2) replace decimalValueStorage[n] = binaryValueStorage[n] * (Math.pow(2, n)); by decimalValueStorage[n] = binaryValueStorage[n] * (Math.pow(2, binaryNumber - n));
Hope this helps!
Well, this is a lot to throw at you, but this is how I'd attack this problem:
public class BinaryToDecimalTest {
private static long binaryToDecimal(String binaryInput)
{
long sum = 0;
for (int i = 0 ; i < binaryInput.length() ; i++) {
sum *= 2;
if (binaryInput.charAt(i) == '1')
sum += 1;
}
return sum;
}
private static void test(String binaryInput) {
long n = binaryToDecimal(binaryInput);
System.out.println(String.format("The Deciaml Value of %s Is %d", binaryInput, n));
}
public static void main(String...args) {
test("0100");
test("1011");
test("1011");
test("10000000");
test("10000000000000000");
}
}
Result:
The Deciaml Value of 0100 Is 4
The Deciaml Value of 1011 Is 11
The Deciaml Value of 1010 Is 10
The Deciaml Value of 10000000 Is 128
The Deciaml Value of 10000000000000000 Is 65536
I don't want to just hit you with code, but I didn't know where to start given all of the issues with your code. I wanted you to see how directly you can often attack a problem. I'd be happy to keep working with you, and explain what's going on here.
The one dirty trick I'm using is multiplying the entire accumulated sum by two each time around. This lets you work naturally from the front of the array, rather than having to work your way backwards. The first digit gets multiplied by 2 (length - 1) times, the second (length - 2) times, etc., down to the last number, which doesn't get multiplied at all.
I have a solution for the Kattis Problem https://open.kattis.com/problems/almostperfect. The solution is accepted, but the runtime is too long (>1.00s).
I tried everything to solve this issue. What can I do to further improve the performance of my code?
import java.io.FileInputStream;
import java.util.Scanner;
import java.io.*;
import java.util.*;
public class almostperfect {
public static int perfect(int number){
// 2 = perfect
// 1 = almost perfect
// 0 = not perfect
int sum = 0;
int b = 0;
for(int i=1;i<number;i++)
{
if(number%i==0)
{
sum = sum + i;
}
}
if(sum == number){
b = 2;
} else if(Math.abs(sum-number)<=2){
b = 1;
}
return b;
}
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
ArrayList<Integer> input = new ArrayList<Integer>();
int a;
int status;
while(scan.hasNextLong()){
input.add((int) scan.nextLong());
}
for(int i=0; i<input.size(); i++){
a = input.get(i);
status = perfect(a);
if(status==2){
System.out.println(a+" perfect");
} else if (status==1){
System.out.println(a+" almost perfect");
} else {
System.out.println(a+" not perfect");
}
}
}}
When you calculate the divisors of number, you don't have to loop from 1 to number, but to the square root of number. Take 100 for example - if 2 is a dividor of 100, so is 100/2.
int sum = 1; //1 is always a divisor
int b = 0;
int sqr = (int)Math.sqrt(number);
for(int i=2;i< sqr;i++)
{
if(number%i==0)
{
sum = sum + i;
sum = sum + number/i;
}
}
//Check what happens for sqr - if it's a divisor, add it only once
if (sqr * sqr == number)
sum += sqr;
Your code is fine, what is not fine is the method of finding the factors for the number it implements. You need to be smarter than brute force checking every possible number smaller than number if it is a factor.
First, obviously 1 is always a factor, since any number divides by 1 without a remainder. Also, by definition the number itself is not a factor. This restricts factors to be found to the range (2 ... n-1).
Second, if you find a divisor, then the dividend is also a divisor:
dividend = number / divisor -> implies: dividend is also a divisor
This means divisors are always found in pairs (dividend is also a divisor, making the pair). The one exception that must be accounted for is that dividend may be the same as dividend (e.g. number = 9, divisor = 3 -> dividend = 3). This can be exploited, leading to:
Third, when starting testing from the smallest possible divisor (2), the first dividend you find is the largest divisor possible, with dividends decreasing steadily while you increase the tested divisor. This means there is no need to explicitly check for divisors that are found as dividend. That means the upper testing limit would be where divisor and dividend become equal, in other words the root of number.
As stated for the problem in the link, numbers may be in range 1 ... 1E9. Your brute force method needs 1 billion tests for 1E9, while the smart version exploiting above properties, only needs 31621. Thats about factor 30000 faster!
So i was calculating e(third row in picture) with numerical methods.
I was increasing the number of elements i used every iteration. And when i executed the program, floating point variable behaved in a way i didn't understand. Here is the program and the result.
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int factorial = 1;
int counter = 0;
int iterationNumber;
double total = 0;
int tempCounter;
System.out.print("Enter iteration number: ");
iterationNumber = input.nextInt();
while (counter <= iterationNumber) {
tempCounter = counter;
while ((tempCounter - 1) > 0) {
factorial *= tempCounter;
tempCounter--;
}
total += ((double)1 / factorial);
System.out.println(total);
factorial = 1;
counter ++;
}
}
}
So my question is why does the value of e starts to decrease after a while instead of increasing? I want to learn how floating point variable behaves during this program and the logic behind it.
Another question is why does it start to say infinity?
n! quickly exceeds Integer.MAX_VALUE and overflows to a negative number. You are then adding a negative number to your total --- thus the decrease.
You can use BigDecimal for your calcualtions. It is slower, but will do the job.
I wrote a solution for a Hackerrank challenge in which I sum a large amount of numbers into a total variable. When I used ints, I noticed I was overflowing in one test case, but all other test cases were outputting the correct answer. When I switched my total variable to a long to avoid overflowing, I started overflowing in two test cases (the same one as before and another one). Once I changed total, numToSell, and lastMax to longs, the program calculate the correct answer.
What would cause this to happen? I would expect that moving a variable from int to long should never cause overflow.
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int T = in.nextInt();
while(T-->0)
{
int N = in.nextInt();
int[] price = new int[N];
for(int i = 0; i < N; ++i)
{
price[i] = in.nextInt();
}
int lastMax = price[N-1]; //works when this and numToSell are longs
int numToSell = 0;
long total = 0; //if this is also an int, only overflows in one case in my samples
for(int i = N - 2; i >= 0; --i)
{
if(price[i] <= lastMax)
{
++numToSell;
total -= price[i];
}
else
{
total += numToSell*lastMax;
lastMax = price[i];
numToSell = 0;
}
}
total += numToSell*lastMax;
System.out.println(total);
}
}
}
In the affected test case N is 39,384 and each number in the array is between 1 and 100000.
Yes, because here
total += numToSell*lastMax;
if numToSell and lastMax are int that's integer multiplication. int * int = int. You then added the int to your long. When numToSell (or lastMax) is a long that particular multiplication instruction will work as you expect. And I note you perform that math in two places.
If total, numToSell, and lastMax, are all ints, there are some cases where things can cancel and give you the correct answer, accidentally. This doesn't necessarily happen if total is long but the other are ints.
Here's an example that walks through the loop.
prices = {2000001,2000000,2000000,2000000};
lastMax = 2000000;
numToSell = 0;
total = 0;
loop:
iteration 1:
numToSell = 1;
total = -2000000
iteration 2:
numToSell = 2;
total = -4000000 // oh no, we underflowed if we are int, but not long!
iteration 3:
total = -4000000 + (2 * 2000000) // let's take a deeper look at this below
numToSell = 0;
lastMax = 20000001
total += 0;
Let's take a look at this line: total = -4000000 + (2 * 2000000)
If total, numToSell, and lastMax are all ints, then total = 0. This is because total underflowed and (2 * 20000000) will overflow in the exact same way. So the two cancel out.
If they are all longs, then nothing overflows so total = -40000000 + (2 * 2000000) = 0.
If total is long, then total did not underflow when it was set to -4000000. But, (2 * 2000000) is an integer, which will overflow and become a negative number. So total will not be zero!
This is a case when having all ints works, having all longs works, but having a mix fails.
I am guessing if you just changed total to long and left numToSell and lastMax as int, then numToSell*lastMax would still overflow and giving you incorrect result which is then added onto total