According to the Java 7 documentation, the method longValue from class java.math.BigDecimal can return a result with the opposite sign.
Converts this BigDecimal to a long. This conversion is analogous to the narrowing primitive conversion from double to short as defined in section 5.1.3 of The Java™ Language Specification: any fractional part of this BigDecimal will be discarded, and if the resulting "BigInteger" is too big to fit in a long, only the low-order 64 bits are returned. Note that this conversion can lose information about the overall magnitude and precision of this BigDecimal value as well as return a result with the opposite sign.
In what case is it possible?
It is possible whenever the value of the BigDecimal is larger than what a long can hold.
Example:
BigDecimal num = new BigDecimal(Long.MAX_VALUE);
System.out.println(num); // prints: 9223372036854775807
System.out.println(num.longValue()); // prints: 9223372036854775807
num = num.add(BigDecimal.TEN); // num is now too large for long
System.out.println(num); // prints: 9223372036854775817
System.out.println(num.longValue()); // prints: -9223372036854775799
System.out.println(num.longValueExact()); // throws: ArithmeticException: Overflow
I will happen if the value is greater than the max value of long
BigDecimal dec = new BigDecimal(Long.MAX_VALUE +1);
System.out.println(dec.longValue());
Related
I have this question:
What do you think would be the value of the variable result after executing the following segment of Java code?
int i = 1234567890;
float f = i;
int result = i - (int)f;
The answer is nonzero
Bear in mind I am a beginner in java currently learning the absolute basics and frankly I do not understand why the answer is nonzero and what each line of the code actually means?
tl;dr
If you want accuracy in your fractional numbers, use BigDecimal class rather than the float floating-point type.
Floating-point is inaccurate
The floating-point technology used by float/Float and double/Double trade away accuracy for speed of execution. Never use these types where accuracy is important, such as money.
So converting an integer to a floating-point number and back again may not result in the same number.
This behavior is not specific to Java. Java implements the electrical engineering standards defining floating-point arithmetic behavior. Any programming language supporting standard floating-point will show the very same issue.
int i = 1234567890; // Create an integer number from literal input, and store as a primitive value in variable named `i`.
float f = i ; // Convert the integer `int` primitive to a fractional number represented using floating-point technology as a primitive value in variable named `f`.
int backAgain = (int)f ; // Cast (convert) from a `float` type to a `int` type. Data-loss may be involved, as any fraction is truncated.
int result = i - backAgain ; // Subtract one `int` primitive from the other `int` primitive. Store the integer result in a primitive `int` variable.
boolean isZero = ( result == 0 ) ; // Test if the result of our subtraction is zero.
See this code run live at IdeOne.com.
i: 1234567890
f: 1.23456794E9
backAgain: 1234567936
result: -46
isZero: false
BigDecimal
If you want accuracy rather than speed when working with fractional numbers, use BigDecimal class.
int i = 1234567890;
BigDecimal bd = new BigDecimal( i ) ;
int backAgain = bd.intValueExact() ;
int result = i - backAgain ;
boolean isZero = ( result == 0 ) ;
See this code run live at IdeOne.com.
isZero: true
i: 1234567890
bd: 1234567890
backAgain: 1234567890
result: 0
isZero: true
In Java, I'm working with the BigDecimal class and part of my code requires me to extract the int part from it. BigDecimal does not appear to have any built in methods to help me get the number before the decimal point of a BigDecimal.
For example:
BigDecimal bd = new BigDecimal("23452.4523434");
I want to extract the 23452 from the number represented above. What's the best way to do it?
Depends on what you mean by "extract". What is the type of the result of the extraction? Another BigDecimal, a BigInteger, an int, a long, a String, or something else?
Here's code for them all:
BigDecimal result1 = bd.setScale(0, RoundingMode.DOWN);
BigInteger result2 = bd.toBigInteger();
int result3 = bd.intValue(); // Overflow may occur
long result4 = bd.longValue(); // Overflow may occur
String result5 = bd.toBigInteger().toString();
String result6 = bd.setScale(0, RoundingMode.DOWN).toString();
NumberFormat fmt = new DecimalFormat("0");
fmt.setRoundingMode(RoundingMode.DOWN);
String result7 = fmt.format(bd);
Explanation of roundings:
RoundingMode.DOWN - Rounding mode to round towards zero. Never increments the digit prior to a discarded fraction (i.e., truncates). Note that this rounding mode never increases the magnitude of the calculated value.
toBigInteger() - Converts this BigDecimal to a BigInteger. This conversion is analogous to the narrowing primitive conversion from double to long as defined in section 5.1.3 of The Java™ Language Specification: any fractional part of this BigDecimal will be discarded. Note that this conversion can lose information about the precision of the BigDecimal value.
intValue() / longValue() - Converts this BigDecimal to an int / long. This conversion is analogous to the narrowing primitive conversion from double to int / long as defined in section 5.1.3 of The Java™ Language Specification: any fractional part of this BigDecimal will be discarded, and if the resulting "BigInteger" is too big to fit in an int, only the low-order 32 / 64 bits are returned.
As can be seen from the descriptions, all 4 discards fractional part, i.e. rounds towards zero, aka truncates the value.
bd.toBigInteger()
See the docs at https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#toBigInteger()
I am trying to convert a BigInteger number into binary. I use a while loop to reduce the BigInteger until it is equal to 1, taking the remainder as the loop runs.
The conditional for the loop is: (decimalNum.intValue()>1).
But the program only goes through the loop once and then thinks that the BigInteger is less/equal to 1 while in reality it is around 55193474935748.
Why is this happening?
("inBinary" is an ArrayList to hold the remainders from the loop.)
Here is the while loop:
while (decimalNum.intValue()>1){
inBinary.add(0, decimalNum.mod(new BigInteger("2")).intValue()); //Get remainder (0 or 1)
decimalNum = decimalNum.divide(new BigInteger("2")); //Reduce decimalNum
}
55,193,474,935,748 doesn't fit into an int: the largest int value is 231 - 1, i.e. 2,147,483,647, which is much smaller. So you get an integer overflow.
This is explained in the javadoc, BTW:
Converts this BigInteger to an int. This conversion is analogous to a narrowing primitive conversion from long to int as defined in section 5.1.3 of The Java™ Language Specification: if this BigInteger is too big to fit in an int, only the low-order 32 bits are returned. Note that this conversion can lose information about the overall magnitude of the BigInteger value as well as return a result with the opposite sign.
If you want to compare a BigInteger to 1, then use
decimalNum.compareTo(BigInteger.ONE) > 0
To get the binary string value of your BigInteger, you could just do
bigInteger.toString(2);
EDIT : As mentionned in the comments by #VinceEmigh, converting BigInteger to int might lead to overflow.
I think that question is pretty straight. but here is an examples.
Example below is OK. I can take rounding and no truncating was done here.
public static void main(String[] args) {
double d = 9.9;
long l = (long)d;
System.out.println(l);
}
Output:
9
And now number out of range of long:
public static void main(String[] args) {
double d = 99999999999999999999999999999999.9;
long l = (long)d;
System.out.println(l);
}
Output:
9223372036854775807
This one troubles me. I cannot continue work with completely different number. I would rather get an error or an exception.
Is there any way to detect this in Java?
You can compare it with Long.MIN_VALUE and Long.MAX_VALUE:
public static boolean fitsLong(double d) {
return d >= Long.MIN_VALUE && d < Long.MAX_VALUE;
}
Somewhat more sofisticated approach is to use BigDecimal:
double value = 1234567.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // 1234568
double value = 99999999999999999999999999999999.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
This way you can control how the rounding is performed.
You may ask, why there's strict inequality in fitsLong: d < Long.MAX_VALUE. Actually that's because the Long.MAX_VALUE itself cannot be represented as double number. When you cast (double)Long.MAX_VALUE, there's not enough precision in double type to represent it, so the closest representable value is selected which is 9223372036854775808.0 (Long_MAX_VALUE+1.0). So were it d <= Long.MAX_VALUE it would return true for number which is actually a little bigger as in this comparison Long.MAX_VALUE constant is promoted to double type. On the other hand Long.MIN_VALUE can be exactly represented in double type, thus here we have >=.
Also it's interesting why the following works:
double value = -9223372036854775809.9; // Long.MIN_VALUE-1.9
System.out.println(fitsLong(value)); // returns true
That's because you actually did not subtract anything from the Long.MIN_VALUE. See:
double d1 = Long.MIN_VALUE;
double d2 = -9223372036854775809.9;
System.out.println(d1 == d2); // true
The double precision is not enough to distinguish between -9223372036854775808 and -9223372036854775809.9, so it's actually the same double number. During the compilation it's converted to binary form, and binary form for these two numbers is the same. Thus having compiled program you cannot distinguish whether -9223372036854775808 or -9223372036854775809.9 was in the source code.
If you feel that it's still the issue, construct the BigDecimal from the String:
long l = new BigDecimal("-9223372036854775808.2")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ok, -9223372036854775808
long l = new BigDecimal("-9223372036854775808.9")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
When you cast a floating point type to an int or long, the result is either the nearest integer (rounding towards zero), or the MIN_VALUE or MAX_VALUE for int or long. See JLS 5.1.3.
Hence, one alternative would be to do the typecast and then test for the appropriate MIN_VALUE or MAX_VALUE.
Note that Long.MAX_VALUE is 9223372036854775807 ... which is the number your test program outputs!
(However, this doesn't work if you are casting a floating point type to byte, char or short. See the link above for the explanation.)
First things first: I come from php and want to widen my horizon with java!
So I read some books. I saw that rounding a number is posible wit Math.round().
My question is as follows:
If I want to round a number as a decimal, I have to use this code:
double number;
number = 1.111222;
number = Math.round(number*100.0) / 100.0;
or
number = (digit) Math.round(number*100) / 100;
But why does
number = Math.round(number*100) / 100;
doesn't do the exact same thing???
Thx in advance,
Marc
If assuming that you mean to put a decimal point for that comma 1.111222
The problem is that 100 will cast the value to a long while 100.0 will cast it to a double. long's cannot have decimals but double's can.
Look at both cases:
Case 1 produces a double:
Math.round(1.111222*100.0) => Math.round(111.222) => 111
111/100.0 => 1.11
Case 2 produces a int long:
(I orignally thought int but was proven wrong by the output, the reason being Math.round(double) returns a long found here)
Math.round(1.111222*100) => Math.round(111) => 111
111/100 => 1 //truncated due to being a long
You can see this by running this code:
public static void main (String[] args)
{
double number = 1.111222;
System.out.println(Math.round(number*100.0)/100.0);
System.out.println(Math.round(number*100)/100);
Object a = Math.round(number*100.0)/100.0;
Object b = Math.round(number*100)/100;
System.out.println(a.getClass().getName());
System.out.println(b.getClass().getName());
}
Which prints:
1.11
1
java.lang.Double
java.lang.Long
It's clear in javadoc.
Returns the closest {#code int} to the argument, with ties rounding up.
So round(float) returns int, and round(double) returns long.
Because Math.round returns a long.
So the result of rounding (of type long) is divided by an int. Before division JVM converts both to long.
See here for Java widening conversion rules.
When you call Math.round(), the result is an integer value. When you divide two integers (e.g. / 100), Java will perform an integer division, throwing away the fractional part of the result.
When you divide an integer by a double (e.g. / 100.0), Java will first convert the integer to a double value, and then perform a floating point division, retaining the fractional part.