Number overflow in Java - java

I am tring to implement C/C++ atoi function in Java, below is the code snippet
for (int j = 0; j < s.length(); j++) {
int digit = Character.digit(s.charAt(j), 10);
if (sum < limit/10) {
if (neg) return Integer.MIN_VALUE;
return Integer.MAX_VALUE;
}
sum *= 10;
if (sum < limit + digit) {
if (neg) return Integer.MIN_VALUE;
return Integer.MAX_VALUE;
}
sum -= digit;
}
For line "if (sum < limit + digit) {", which is correct, however, if I use "sum - digit < limit", it will get wrong result, e.g. input "-2147483649", wrong result 2147483647, should be -2147483648.
I figured this out, cuz sum - digit might be overflow, so this come to another question:
int sum = Integer.MAX_VALUE;
System.out.println(sum < Integer.MAX_VALUE + 1);
Why this prints false? What is the behind logic?

Integer.MAX_VALUE + 1 is equal to Integer.MIN_VALUE, which will be more obvious if you look at them in hexadecimal:
Integer.MAX_VALUE = 0x7fffffff
1 = 0x00000001
---------- +
0x80000000
And 0x80000000 is also known as Integer.MIN_VALUE.
Obviously there's no int lower than Integer.MIN_VALUE.
Also, attempting to test whether a number has overflowed by seeing if it's bigger than the biggest possible value is fundamentally misguided. It can't be bigger than the biggest possible value, that's what "biggest possible" implies. Also, you can't take a number, look at it, and determine whether it has overflowed or not, because every number can be the result of a non-overflowing computation (and indeed of just writing it down as a constant) and as the result of a computation that overflowed. You need to know how you got that number.

If you add Integer.MAX_VALUE and 1, then that sum will overflow, so sum won't be less than the resultant "sum", Integer.MIN_VALUE, so it's false.
To get that to work properly, you can cast Integer.MAX_VALUE as a long so overflow won't occur, and the comparison will work properly.
System.out.println(sum < (long) Integer.MAX_VALUE + 1);
Output:
true

FYI: Integer.parseInt(String) does what you are writing.
Why this prints false? What is the behind logic?
System.out.println(sum < Integer.MAX_VALUE + 1);
This prints false, because Integer.MAX_VALUE + 1 == Integer.MIN_VALUE. So this is equivalent with
System.out.println(sum < Integer.MIN_VALUE);
There is nothing smaller than the minimum value.

Related

How to compute the integer m such that m^3 <= Long.MAX_VALUE < (m + 1)^3 by Java language?

I want to know the long m such that m*m*m <= Long.MAX_VALUE && Long.MAX_VALUE < (m + 1)*(m + 1)*(m + 1).
How can I compute the above long m?
I am worried about overflow and I don't know about overflow at all.
You don't need Java to solve this.
Long.MAX_VALUE == (2^63)-1. If n == 2^(63/3) = 2^21, then n*n*n = 2^63. So, (m+1) == 2^21, and hence m == (2^21)-1.
If you want to write some code to convince yourself of this:
long m = (1L << 21) - 1;
System.out.println(m*m*m); // 9223358842721533951
System.out.println(m*m*m < Long.MAX_VALUE); // true
long n = m + 1;
System.out.println(n*n*n); // -9223372036854775808
So n*n*n has obviously overflowed, because its value is negative.
(Note that if the result were positive, or even greater than m*m*m, this wouldn't be evidence that it hadn't overflowed. It's just coincidence that the overflow is so apparent).
You can also use Long.compareUnsigned:
// Negative, so m*m*m < Long.MAX_VALUE)
System.out.println(Long.compareUnsigned(m*m*m, Long.MAX_VALUE));
// Positive, so unsigned n*n*n > Long.MAX_VALUE)
System.out.println(Long.compareUnsigned(n*n*n, Long.MAX_VALUE));
Thank you very much, c0der.
I can use Math.cbrt() function to get the answer.
And I can check the answer is right by Andy Turner's method.
long m1 = (long) Math.cbrt((double) Long.MAX_VALUE);
System.out.println(m1*m1*m1);
m1++;
System.out.println(m1*m1*m1);
Is this ok?
long i = 0, j = 1;
while (i*i*i < j*j*j) {
i++;
j++;
}
Sytem.out.println(i);

To reach the target number from 0 in minimum number of steps

Problem Statement:
Find the minimum number of steps required to reach a target number x from 0 (zero), using only two operations: +1 (add 1 to the number) or *2 (multiply 2 with the number).
So here's the Logic that I came up with:
The best way is to work backwards. Start from the number you need:
Subtract 1 if the number is odd.
Divide by 2 if the number if even.
Stop when you get to zero.
For example, for 29, you get 28, 14, 7, 6, 3, 2, 1, 0.
And, here's what I have tried doing (Java 7):
kValues is an array that has the x values for which the steps are needed to be computed and stored in an array called result.
static int[] countOperationsToK(long[] kValues) {
int size = kValues.length,x,i,steps;
int result[] = new int[size];
for (i = 0; i < size; ++i)
{
steps = 0;
for (x = (int)kValues[i]; x != 0 ; ++steps)
{
if((x % 2) == 0)
x /= 2;
else x--;
}
result[i] = steps;
}
return result;
}
My Problem:
This is a Hackerrank question and I am supposed to write an efficient code. I was successful with 7/11 test cases and others were timed out. Since, it is a Hackerrank question, I can't change the function definition or the return type. That is the reason why I am converting from long to int in my for loop, in order to use % (modulus). I would like to know where I am going wrong. Is my algorithm taking too long to compute (for the number of values close to a million)? Which is obviously the case, but how do I alter my algorithm in order to pass all the test cases?
Thank you in advance :)
for (x = (int)kValues[i]; x != 0 ; ++steps)
The fact that you are casting a long to an int is very suspicious. You might get a negative number when you do that.
Say x == -2: you divide it by 2 to give -1, then subtract 1 to give -2. You'll keep doing that indefinitely.
Just define x to be a long, and remove the cast.
So, here's the working code. I had forgotten to append L while using the modulo. Silly mistake led to so much of typing. LOL!!
static int[] countOperationsToK(long[] kValues) {
int size = kValues.length,i,steps;
int result[] = new int[size];
long x;
for (i = 0; i < size; ++i)
{
steps = 0;
for (x = kValues[i]; x != 0 ; ++steps)
{
if((x % 2L) == 0)
x /= 2L;
else x -= 1L;
}
result[i] = steps;
}
return result;
}
Here is a very short version, using bit-analysis:
static int[] countOperationsToK(long... input) {
int result[] = new int[input.length];
for (int i = 0; i < input.length; i++)
if (input[i] > 0)
result[i] = Long.bitCount(input[i]) + 63 - Long.numberOfLeadingZeros(input[i]);
return result;
}
The idea here is to look at the binary number, e.g. for 29 that is 11101. There are 4 bits set, so we'd need to do +1 four times, and the highest bit position is 4, so we need to left-shift (i.e. *2) four times, for a total of 8 operations: +1, *2, +1, *2, +1, *2, *2, +1.
numberOfBits = Long.bitCount(x)
highBitNumber = floor(log2(x)) = 63 - Long.numberOfLeadingZeros(x)
The highBitNumber part doesn't work if value is zero, hence the if statement.
For input number x,
Minimum no. of Ops = (int)log2(x) + Long.BitCount(x)

Sum the first N numbers in java

Hello, I am new to programming and I am trying to write a small program where it will calculate the sum for first N numbers. The problem is it does not work for even numbers. I have not managed to figure out why.
My code is as follow:
int n = Integer.parseInt(args[0]);
int sum = (1+n)/2*n;
System.out.println(sum + " is the sum of first " + n + " numbers");
It doesn't work for even n because (n+1)/2 is truncated to an int.
This means that if, for example, n=4, (n+1)/2 results in 2 instead of 2.5, so when you multiply it by n, you get 8 instead of the desired 10.
You can overcome this problem simply by changing the order of the operations. If you first multiply n by (n+1), the result is guaranteed to be even, so dividing it by 2 will produce the correct answer.
int sum = n*(1+n)/2;
You have integer division with (1+n)/2. If your number is even, then (1+n) is odd and the division by 2 will truncate any decimal result, so that an int divided by an int is still an int.
Multiply by n first, then divide by 2. This ensures that the product is even before dividing, so the result is correct.
int sum = (1+n) * n / 2;
One can use ((n * (n + 1)) / 2). But I think the following will work without overflow errors for a few additional values of n:
if ((n & 1) == 0) {
sum = ((n >> 1) * (n + 1));
} else {
sum = (n * ((n + 1) >> 1));
}

sum(1/prime[i]^2) >= 1?

While trying to devise an algorithm, I stumbled upon this question. It's not homework.
Let P_i = an array of the first i primes. Now I need the smallest i such that
Sum<n=0..i> 1 / (P_i[n]*P_i[n]) >= 1.
(if such i exists).
An approximation for the i'th prime is i*log(i). So I tried this in Java:
public static viod main(String args[]) {
double sum = 0.0;
long i = 2;
while(sum<1.0) {
sum += 1.0 / (i*Math.log(i)*i*Math.log(i));
i++;
}
System.out.println(i+": "+sum);
}
However the above doesn't finish because it converges to 0.7. However 1/100000000^2 rounds to 0.0 in Java, so that's why it doesn't work. For the same reason it doesn't even work if you replace the 6th line with
sum += 1.0 / (i*i)
while that should reach 1 if I'm not mistaken, because the sum should incease faster than 1/2^i and the latter converges to 1. In other words, this shows that Java rounding causes the sum to not reach 1. I think that the minimum i of my problem should exist.
On the maths side of this question, not the java side:
If I understand the problem, there is no solution (no value of i).
For any finite set P_i of primes {p_1, p_2,...p_i} let N_i be the set of all integers up to p_i, {1,2,3,...,p_i}. The sum 1/p^2 (for all p_n in P_i) will be less than the sum of all 1/x^2 for x in N_i.
The sum of 1/x^2 tends to ~1.65 but since 1 will never be in the set of primes, the sum is limited by ~0.65
You cannot use double for this, because it is not uniform. You should use fractions. I found this class https://github.com/kiprobinson/BigFraction
Then I tried to find whats happening :
public static void main(String args[]) {
BigFraction fraction = BigFraction.valueOf(1, 4);
int n = 10000000, status = 1, num = 3;
double limit = 0.4;
for (int count = 2; count <= n;) {
for (int j = 2; j <= Math.sqrt(num); j++) {
if (num % j == 0) {
status = 0;
break;
}
}
if (status != 0) {
fraction = fraction.add(BigFraction.valueOf(1,BigInteger.valueOf(num).multiply(BigInteger.valueOf(num))));
if (fraction.doubleValue() >= limit){
System.out.println("reached " + limit + " with " + count + " firsts prime numbers");
limit += 0.01;
}
count++;
}
status = 1;
num++;
}
}
This is having this output :
reached 0.4 with 3 firsts prime numbers
reached 0.41000000000000003 with 4 firsts prime numbers
reached 0.42000000000000004 with 5 firsts prime numbers
reached 0.43000000000000005 with 6 firsts prime numbers
reached 0.44000000000000006 with 8 firsts prime numbers
reached 0.45000000000000007 with 22 firsts prime numbers
And nothing more in a minute. I debug it and found that it grows extremely slower and slower, I do not think, it can reach 1 even in infinity :) (but dont know how to prove it).
I guess you might loose the precision you need when you use default Math.log multiplied by float i. I think this can be handled by using an appropriate RoundingMode. Please see setRoundingMode

Prime factorization algorithm fails for big numbers

I have run into a weird issue for problem 3 of Project Euler. The program works for other numbers that are small, like 13195, but it throws this error when I try to crunch a big number like 600851475143:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at euler3.Euler3.main(Euler3.java:16)
Here's my code:
//Number whose prime factors will be determined
long num = 600851475143L;
//Declaration of variables
ArrayList factorsList = new ArrayList();
ArrayList primeFactorsList = new ArrayList();
//Generates a list of factors
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
factorsList.add(i);
}
}
//If the integer(s) in the factorsList are divisable by any number between 1
//and the integer itself (non-inclusive), it gets replaced by a zero
for (int i = 0; i < factorsList.size(); i++)
{
for (int j = 2; j < (Integer) factorsList.get(i); j++)
{
if ((Integer) factorsList.get(i) % j == 0)
{
factorsList.set(i, 0);
}
}
}
//Transfers all non-zero numbers into a new list called primeFactorsList
for (int i = 0; i < factorsList.size(); i++)
{
if ((Integer) factorsList.get(i) != 0)
{
primeFactorsList.add(factorsList.get(i));
}
}
Why is it only big numbers that cause this error?
Your code is just using Integer, which is a 32-bit type with a maximum value of 2147483647. It's unsurprising that it's failing when used for numbers much bigger than that. Note that your initial loop uses int as the loop variable, so would actually loop forever if it didn't throw an exception. The value of i will go from the 2147483647 to -2147483648 and continue.
Use BigInteger to handle arbitrarily large values, or Long if you're happy with a limited range but a larger one. (The maximum value of long / Long is 9223372036854775807L.)
However, I doubt that this is really the approach that's expected... it's going to take a long time for big numbers like that.
Not sure if it's the case as I don't know which line is which - but I notice your first loop uses an int.
//Generates a list of factors
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
factorsList.add(i);
}
}
As num is a long, its possible that num > Integer.MAX_INT and your loop is wrapping around to negative at MAX_INT then looping until 0, giving you a num % 0 operation.
Why does your solution not work?
Well numbers are discrete in hardware. Discrete means thy have a min and max values. Java uses two's complement, to store negative values, so 2147483647+1 == -2147483648. This is because for type int, max value is 2147483647. And doing this is called overflow.
It seems as if you have an overflow bug. Iterable value i first becomes negative, and eventually 0, thus you get java.lang.ArithmeticException: / by zero. If your computer can loop 10 million statements a second, this would take 1h 10min to reproduce, so I leave it as assumption an not a proof.
This is also reason trivially simple statements like a+b can produce bugs.
How to fix it?
package margusmartseppcode.From_1_to_9;
public class Problem_3 {
static long lpf(long nr) {
long max = 0;
for (long i = 2; i <= nr / i; i++)
while (nr % i == 0) {
max = i;
nr = nr / i;
}
return nr > 1 ? nr : max;
}
public static void main(String[] args) {
System.out.println(lpf(600851475143L));
}
}
You might think: "So how does this work?"
Well my tough process went like:
(Dynamical programming approach) If i had list of primes x {2,3,5,7,11,13,17, ...} up to value xi > nr / 2, then finding largest prime factor is trivial:
I start from the largest prime, and start testing if devision reminder with my number is zero, if it is, then that is the answer.
If after looping all the elements, I did not find my answer, my number must be a prime itself.
(Brute force, with filters) I assumed, that
my numbers largest prime factor is small (under 10 million).
if my numbers is a multiple of some number, then I can reduce loop size by that multiple.
I used the second approach here.
Note however, that if my number would be just little off and one of {600851475013, 600851475053, 600851475067, 600851475149, 600851475151}, then my approach assumptions would fail and program would take ridiculously long time to run. If computer could execute 10m statements per second it would take 6.954 days, to find the right answer.
In your brute force approach, just generating a list of factors would take longer - assuming you do not run out of memory before.
Is there a better way?
Sure, in Mathematica you could write it as:
P3[x_] := FactorInteger[x][[-1, 1]]
P3[600851475143]
or just FactorInteger[600851475143], and lookup the largest value.
This works because in Mathematica you have arbitrary size integers. Java also has arbitrary size integer class called BigInteger.
Apart from the BigInteger problem mentioned by Jon Skeet, note the following:
you only need to test factors up to sqrt(num)
each time you find a factor, divide num by that factor, and then test that factor again
there's really no need to use a collection to store the primes in advance
My solution (which was originally written in Perl) would look something like this in Java:
long n = 600851475143L; // the original input
long s = (long)Math.sqrt(n); // no need to test numbers larger than this
long f = 2; // the smallest factor to test
do {
if (n % f == 0) { // check we have a factor
n /= f; // this is our new number to test
s = (long)Math.sqrt(n); // and our range is smaller again
} else { // find next possible divisor
f = (f == 2) ? 3 : f + 2;
}
} while (f < s); // required result is in "n"

Categories