According to the specification of Number.longValue()
the method should...
Returns the value of the specified number as a long. This may involve rounding or truncation.
However, the BigInteger
(and BigDecimal
) overrides this method and returns the 64 low bits of the integer part of the number it represents. From the docs of BigInteger
for example:
[...]if this BigInteger is too big to fit in a long, only the low-order 64 bits are returned.[...]
I claim that either "This may involve rounding or truncation." doesn't say anything about what the method actually should return, or, there is a bug in implementation or documentation.
Would you agree, or do I have a mistake in my reasoning?
Example code:
import java.math.BigInteger;
import static java.math.BigInteger.*;
public class Main {
public static void main(String[] args) {
BigInteger i = valueOf(Long.MAX_VALUE);
// Result: Long.MAX_VALUE, just as expected.
Number n1 = i;
System.out.println(n1 + " -> " + n1.longValue());
// I expect to get the "rounded" value Long.MAX_VALUE
Number n2 = i.add(ONE);
System.out.println(n2 + " -> " + n2.longValue());
// I expect to get the "rounded" value Long.MAX_VALUE
Number n3 = i.multiply(TEN);
System.out.println(n3 + " -> " + n3.longValue());
}
}
Output:
9223372036854775807 -> 9223372036854775807
9223372036854775808 -> -9223372036854775808
92233720368547758070 -> -10
The wording "This may involve rounding or truncation" appears in the javadocs for the longValue()
, shortValue()
, charValue()
and byteValue()
of Number
, so it is clear that "truncation" is intended to include loss of significant high order bits in some cases.
The problem really is that the term "truncation" conventionally means loss of lower order bits. (That's how I remember it from my numerical analysis course, 30 years ago. And Wikipedia agrees.)
By contrast, the JLS 5.1.3 describes the same process (when narrowing integral primitive types) as follows:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T.
So yes, I agree that the javadoc is incorrect. Submit a bug report.
NOTE
I had originally deleted this because I thought my suggestion to submit a bug report was probably futile (based on my past experience with documentation bug reports). But @aioobe has submitted a bug report ... (Bug ID: 7000825)
The documentation of BigInteger.longValue()
continues with:
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.
This redefines (or clarifies) the behaviour defined by Number.longValue()
. This is fine, although it is sometimes misleading. For example java.util.Set
redefines the behaviour of the add
method (by constraining duplicates). If you pass a Collection
you may expect it to hold any values, but the concrete implementation has redefined this behaviour.
Update: I checked how does Long.valueOf(Long.MAX_VALUE).intValue()
behaves. And it prints -1. So I'd assume that by "round or truncate" is just a possibility, regarding floating point numbers. Otherwise the Number
class leaves the way of conversion entirely to implementors. So yes - it does not tell anything about it. I wouldn't say it is that bad, but it is certainly misleading.
I don't see your question, how is this any different from the garbage you get whenever you try and represent a number outside the bounds of a particular numeric type?
final Number n = Long.MAX_VALUE;
System.out.println(n + " -> " + n.intValue());
prints
9223372036854775807 -> -1
Do you want the API to tell you that you'll get invalid output if you pass invalid input?