jOOQ / jOOU

jOOU - Unsigned Integers jOOU provides unsigned integer versions for the four Java integer types byte, short, int and long.
http://www.jooq.org/products
Apache License 2.0
228 stars 32 forks source link

UInteger range inconsistencies #12

Open unserializable opened 7 years ago

unserializable commented 7 years ago

Unsigned integer range handling has incorrectnesses / inconsistencies.

E.g. UInteger can be formed from integer -34 but not from long -34.

@Test
public void test_negative_uint_34il() {
    UInteger a = uint(-34);
    UInteger b = uint(-34L);
    assertTrue (a == b);
}

Reported error is Exception in thread "main" java.lang.NumberFormatException: Value is out of range : -34 for the b definition.

I would either expect both of the samples below to fail or succeed, but not act differently. What is the intent in this library? Shouldn't both these cases succeed, since -34 is a value that is representable in 32 bit signed integer?

lukaseder commented 7 years ago

Thanks for reporting. Yes, that does look weird because you see two times the value -34. But the intention of the two constructors is quite different, in fact. as documented in the Javadoc.

lukaseder commented 7 years ago

... in other words, the behaviour is expected and consistent across all types, i.e. you'll find the same duality in ubyte(byte) vs ubyte(short) or ushort(short) vs. ushort(int) or ulong(long) vs. ulong(BigInteger)

unserializable commented 7 years ago

Thanks for the quick reply, @lukaseder! My project javadocs from attached sources don't contain the references you quote. Is the jOOU version which documentation you are referring to available from Maven repositories?

But as you said the following:

uint(long) takes the least significant 32 bits from the argument long value and treats that as an unsigned integer. In this case, -34 is simply out of range

the long handling seems even more weird, as it would be always possible to take least significant 32 bits from the long and treat that them as unsigned integer. The results for anything that fits into 32-bit signed integer should be identical too. Illustrating with -34 again:

String longBitString = Long.toBinaryString(-34L);
String intBitString = Integer.toBinaryString(-34);
System.out.printf("%64s%n", longBitString);
System.out.printf("%64s%n", intBitString);

which shows that the last 32 bits of long -34 are the same as full 32 bits of int -34.

1111111111111111111111111111111111111111111111111111111111011110
                                11111111111111111111111111011110
                                ^                               

One can of course do the int cast to get the last 32-bits of the long and then make an uint out of it, but doesn't that kind of defeat the purpose of the uint(long) when one needs to use uint((int)-34L) anyway, to bypass the NumberFormatException? Actual usage in code is not using long constants of course, but variables of type long.

lukaseder commented 7 years ago

The Javadoc is available here: https://www.jooq.org/products/jOOU/javadoc/latest ... And it should also be available from Maven Central.

lukaseder commented 7 years ago

Interesting comment, you're right of course. That could be a design goal. Currently, the most significant 32 bits are required to be all zero, but we don't have to require this in principle. It would lead to the obvious discussion about "clever convenience" vs. "failing early". And it would probably also complicate the ULong type.

But I'm willing to review this change request.