The code below shows an error due to lossy conversion because math.pow returns a double, and I store the answer in an integer.
int k = 0
k = k + Math.pow(2, 4);
System.out.println(k);
but this code:
int k = 0
k += Math.pow(2, 4);
System.out.println(k);
Shows no error, why?
My question is: Why is there no error in the second code?
Here, += does implicit cast, where as + operator requires
explicit cast for second operand, otherwise it won’t compile.
So in the first code, we are assigning the right side part (k + Math.pow(2,4)) which becomes double after additon and assigning it to an int type variable at last. And that's an issue of lossy conversion.
If we explain the second code snippet,
int k = 0
k += Math.pow(2, 4);
System.out.println(k);
as per the java documentation we can see it's internal working like this:
int k = 0
k = (int) (k + Math.pow(2, 4));
System.out.println(k);
You can see in the doc here.
Related
I was trying to convert the array to integer sum=999999999999 (twelve 9) , when i am limiting the array to less than ten 9s it is giving the result but when i am giving the array of more than ten 9s it is giving an unexpected result , please explain it will be really helpful for me
int[] arr={9,9,9,9,9,9,9,9,9,9,9,9};
int p=arr.length-1;
int m;
int num=0;
for (int i = 0; i <= p; i++) {
m=(int) Math.pow(10, p-i);
num += arr[i]*m; // it is executing like: 900+90+9=999
}
this happens because you're exceeding the Integer.MAX_VALUE.
You can read about it here.
You can use instead of int a long, to store large values,
and if that is not enough for you, you can use - BigInteger
BigInteger num = BigInteger.valueOf(0);
for (int i = 0; i <= p; i++) {
BigInteger m = BigInteger.valueOf((int) Math.pow(10, p-i));
BigInteger next = BigInteger.valueOf(arr[i]).multiply(m));
num = num.add(BigInteger.valueOf(arr[i]*m));
}
A couple of things.
You don't need to use Math.pow.
for up to 18 digits, you can use a long to do the computation.
I added some extra digits to demonstrate
int[] arr={9,9,9,9,9,9,9,9,9,9,9,9,1,1,2,3,4};
long sum = 0; // or BigInteger sum = BigInteger.ZERO;
for (int val : arr) {
sum = sum * 10 + val; // or sum.multiply(BigInteger.TEN).add(BigInteger.valueOf(val));
}
System.out.println(sum);
prints
99999999999911234
Here is the sequence for 1,2,3,4 so you can see what is happening.
- sum = 0
- sum = sum(0) * 10 + 1 (sum is now 1)
- sum = sum(1) * 10 + 2 (sum is now 12)
- sum = sum(12)* 10 + 3 (sum is now 123)
- sum = sum(123)*10 + 4 (sum is now 1234)
It is because an int is coded on 4 byte so technically you can only go from -2,147,483,648 to 2,147,483,647.
Consider using the long type.
Try using long (or any other type which can represent larger numbers) instead of int.
I suggest this because the int overflows: see https://en.wikipedia.org/wiki/Integer_overflow
Because it overflows integer boundry. The maximum integer value that can be stored in Java is 2147483647. When you try to store a value greater than this, the result will be an unexpected value. To solve this issue, you can use a long data type instead of an int data type
you can read about it here and here
I ran below program in C++(Dec-c++) :
int k = 5;
k = k++;
cout<<"Value of K :"<<k<<endl;
int l = 5;
l = l++ + l++;
cout<<"Value of L :"<<l<<endl;
int m = 5;
m = m++ + m++ + m++;
cout<<"Value of M :"<<m<<endl;
and got 5,12 and 18 for variables k,l and m.. But same program when I ran in java --
int k = 5;
k = k++;
System.out.println("Value of K :"+k);
int l = 5;
l = l++ + l++;
System.out.println("Value of L :"+l);
int m = 5;
m = m++ + m++ + m++;
System.out.println("Value of M :"+m);
I got 5,11 and 18 for variables k,L and M..
Explain why there is difference in calculations of unary post operators ? I am aware of operator's precedence and priority rules. But every thing fails here. But answer from c++ seems rational according to rules. Confused how java is calculating ?
It's well known C++ and Java are different. Please Suggest how operator-precedence and operator-priority is handled in Java.
The rule for Java is quite simple here. The sub-expressions (each call to the postfix operator) are evaluated left to right, each one being fully evaluated before the next.
int k = 5;
k = k++;
This increments k to 6, but returns its previous value (5) and reassigns that to k. So k is 5.
int l = 5;
l = l++ + l++;
The first l++ increments l to 6, and evaluates to its previous value (5). Then the next l++ is called, which increments l to 7, and evaluates to 6. The 5 and 6 are added together and assigned to l, resulting in 11.
int m = 5;
m = m++ + m++ + m++;
Using the same process as before, we just do it one more time, so this is equivalent to adding 5 + 6 + 7 and assigning the result to m, which becomes 18.
The C++, despite your claim that you understand it, is not so simple. In fact, it is undefined behavior, as thoroughly explained in the answers to this question. There are no rules, and you can see any results whatsoever. Don't do it.
In the following Java program I cannot understand what this line does:
wert = (wert * mult + inkr) & 0x7FFFFFFFL;
I understand what the bitwise operators do in conditions, but there are principally two numbers (the hexadecimal is the maximum value of Integers in Java). I do not understand, why the & 0x7FFFFFFFL; has even some influence in this line. In my opinion, the variable wert should simply have the value of (wert * mult + inkr) because it's true.
Though I figured out that the & 0x7FFFFFFFL; obviously does have some influence only if (wert * mult + inkr) is negative. Why and what exactly happens in this line?
Annotation: This should be a program for simulating a lottery drawing. I am aware of the error in the program, right where the comment is. But this is not relevant for me right now.
Still it would be great if someone could me tell following not really Java-specific question: what sense got the variables mult and inkr?
public static void main(String args[]) {
int kugeln = 49;
int ziehen = 6;
int mult = 1103515245;
int inkr = 12345;
long wert = System.currentTimeMillis();
int zahlen[] = new int[kugeln];
for(int i = 0; i < kugeln; i++) {
zahlen[i] = i + 1;
wert = (wert * mult + inkr) & 0x7FFFFFFFL;
}
for(int i = 0; i < ziehen; i++) {
int index = (int)(wert / 10) % (49 - i);
int temp = zahlen[49 - i]; // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 49
zahlen[49 - i] = zahlen[index];
zahlen[index] = temp;
wert = (wert * mult + inkr) & 0x7FFFFFFFL;
}
int superzahl = (int)(wert / 10) % 10;
for(int i = 0; i < ziehen; i++) {
System.out.println(zahlen[49 - i]);
}
System.out.println(superzahl);
}
Using bitwise AND with non-booleans will bitwise AND together all of the bits of the two numbers one by one.
In this case, the number 0x7FFFFFFFL is the hexadecimal representation of a number that is a 0 bit followed by 31 1 bits:
01111111111111111111111111111111
By ANDing this with an integer, you preserve the lower 31 bits (since 1 & x = x for any x) and clear the highest bit (since 0 & x = 0 for any x). Since Java uses a 32-bit signed two's-complement representation, this has the effect of clearing the sign bit, forcing the number to be positive.
My guess is that this program is using some sort of rolling hash function where the resulting number has to be positive. To do this, the code constantly updates the integer by combining it with more and more information, and at each step forces the number to be positive by clearing the sign bit.
Hope this helps!
Anding with 0x7FFFFFFFL results in only the 31 lowest bits getting included, the others get set to 0. The result is always positive because the sign bit is masked out.
int temp = zahlen[49 - i]; // Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: 49
i is starting from 0 so zahlen[49 ] is called
int zahlen[] = new int[kugeln];
int kugeln = 49;
int a[] = new int [49];
a[49] will throw an exception always. Fom there is your exception.
Why do the following two operations yield different results in Java for x = 31 or 32 but the same results for x=3?
int x=3;
int b = (int) Math.pow(2,x);
int c = 1<<x;
Results:
x=32: b=2147483647; c=1;
x=31: b=2147483647; c=-2147483648;
x=3: b=8 ; c=8
There are multiple issues at play:
An int can only store values between -2147483648 and 2147483647.
1 << x only uses the lowest five bits of x. Thus, 1 << 32 is by definition the same as 1 << 0.
Shift operations are performed on the two's-complement integer representation of the value of the left operand; this explains why 1 << 31 is negative.
Math.pow(2, 32) returns a double.
(int)(d), where d is a double greater than 2147483647 returns 2147483647 ("the largest representable value of type int").
What this interview question does is show that (int)Math.pow(2, x) and 1 << x are not equivalent for values of x outside the 0...30 range.
P.S. It is perhaps interesting to note that using long in place of int (and 1L in place of 1) would give yet another set of results different from the other two. This holds even if the final results are converted to int.
According to the documentation Math.pow will promote both of its arguments to double and return double. Obviously when the returned result is double and you cast it to int you'll get only the highest 32 bits and the rest will be truncated - hence you always get the (int) Math.pow(2,x); value. When you do bitshift you always work with ints and hence an overflow occurs.
Consider the limits of the type int. How large a number can it hold?
Here's a micro-benchmark for the case of a long. On my laptop (2.8GHz), using shift instead of Math.pow is over 7x faster.
int limit = 50_000_000;
#Test
public void testPower() {
Random r = new Random(7);
long t = System.currentTimeMillis();
for (int i = 0; i < limit; i++) {
int p = r.nextInt(63);
long l = (long)Math.pow(2,p);
}
long t1 = System.currentTimeMillis();
System.out.println((t1-t)/1000.0); // 3.758 s
}
#Test
public void testShift() {
Random r = new Random(7);
long t = System.currentTimeMillis();
for (int i = 0; i < limit; i++) {
int p = r.nextInt(63);
long l = 1L << p;
}
long t1 = System.currentTimeMillis();
System.out.println((t1-t)/1000.0); // 0.523 s
}
int is 32 bits in size and since it is signed (by default), the first bit is used for the sign. When you shift left 31 bits, you get the Two's Compliment, which is -(2^32). When you shift left 32 bits, it just loops all the way back around to 1. If you were to do this shifting with longs instead of ints, you would get the answers you expect (that is until you shift 63+ bits).
I came across the following silly function here:
public static String findOutWhatLifeIsAllAbout() {
int meaning = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 20; j++) {
for (int k = 0; k < 300; k++) {
for (int m = 0; m < 7000; m++) {
meaning += Math.random() + 1;
}
}
}
}
return String.valueOf(meaning).replaceAll("0*$", "");
}
In summary, the expected result is a string "42", since Math.random() returns doubles "greater than or equal to 0.0 and less than 1.0". In practice, running on an i5 under Ubuntu the resulting strings are similar to "420000011", "420000008"! (meaning sometimes Math.random()'s result is getting rounded up!
To get a grip on what sorts of double values would cause Math.random()'s result to somehow round to 1, I tried this function instead, expecting to see some examples.
public static String findOutWhatLifeIsAllAboutAltered() {
int meaning = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 20; j++) {
for (int k = 0; k < 300; k++) {
for (int m = 0; m < 7000; m++) {
double randomResult = Math.random();
int converted = randomResult;
if (converted > 0) {
System.out.println("Misbehaving double = " + randomResult);
}
meaning += converted + 1;
}
}
}
}
return String.valueOf(meaning).replaceAll("0*$", "");
}
However this formulation always returns "42"! Can anyone offer insight about why the behavior changes in the altered function? Thanks.
Furthermore why does Java let the original function compile at all? Shouldn't there be a loss-of-precision error at the += call?
edit posted the code I wanted you all to see - the "original" version wasn't supposed to have a cast.
There's a small but important difference between the code in the link and the code originally posted here,
meaning += Math.random() + 1; // link
vs.
meaning += (int)Math.random() + 1; // StackOverflow
If the code posted here prints out anything but 42, it's a serious bug.
Here, the result of Math.random() is explicitly cast to int, that must result in 0, then 1 is added, resulting in 1, which then is added to meaning.
The code in the linked post, however performs an implicit cast to int after adding the result of Math.random() to 1 and that to meaning, basically
meaning = (int)(Math.random() + (double)1 + (double)meaning);
Now, if the result of Math.random() is close enough to 1.0, it occasionally happens that the result of the double addition is rounded up, so producing a final result slightly larger than immediately expected.
Shouldn't there be a loss-of-precision error at the += call?
No. In the first case, you're explicitly casting the value returned by Math.random() to an int. In the second case, meaning, converted, and 1 are all integers.
There is, however, a possible loss-of-precision at this line:
int converted = randomResult;
http://ideone.com/1ZTDi
There won't be a loss of precision error at all because they're all ints in this example - you're not actually adding any doubles!
The only line where you could be you're casting the result of Math.random() to an int - so you're still just adding two ints together.
However, even if you were adding doubles to an int then there still wouldn't be because the JLS defines an implicit cast for these types of operators:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
Source:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.26.2
Loss of precision could only come on these lines as you're doing type conversion:
double randomResult = Math.random();
int converted = randomResult;
As Math.random() returns an double which is between 0.0 inclusive and 1.0 exclusive, the variable converted will only ever contain 0 as it's converted to an int.
For more on the casting from a double > int, see here: Different answer when converting a Double to an Int - Java vs .Net
I've tried your original program on a Java 6 system running on Mac OS X (Lion) and it only outputs 42. Which JRE/JDK are you using?