22. Hooking Java (un)signed integers in a nutshell

Signed values (or variables) such as signed integers or signed longs allow us to represent negative and positive numbers. Unsigned values (or variables) such as unsigned integers or unsigned longs allow us to represent only positive numbers. Signed and unsigned values (variables) of the same type share the same range. But, as you can see in the following figure, unsigned variables cover a larger magnitude number.

Figure 1.20 – Signed and Unsigned integers

The signed 32-bit integers range from –2,147,483,648 to 2,147,483,647 (around 4 billion values). Unsigned 32-bit integers range from 0 to 4,294,967,295 (also around 4 billion values). So, when we use signed integer variables, we can use 2 billion positive values, but when we use unsigned integer variables, we can use 4 billion positive values. The hatched part of the figure represents the extra 2 billion positive integer values.Commonly, unsigned values are needed when we don’t need negative values at all (for instance, to count something like an event occurrence) and we need to use values that resign in the hashed area in figure 1.20. Java supports only signed integers that use the popular two’s complement representation in a signed system (for a detailed explanation of two’s complement representation and bit manipulation please check out The Complete Coding Interview Guide in Java, Chapter 9, Bit Manipulation). But, starting with JDK 8, we also have the Unsigned Integer API which adds support for unsigned arithmetic. Practically, we talk about a bunch of static methods added in Integer and Long classes. They are all covered in Java Coding Problems, First Edition, Problems 27(String as an unsigned number in the radix), 28 (Converting into a number by an unsigned conversion), 29 (Comparing two unsigned values), and 30 (Division and modulo of unsigned values).Moreover, JDK 9, comes with a method named Math.multiplyHigh(long x, long y). This method returns a long representing the most significant 64 bits of the 128-bit product of two 64-bit factors. The following figure clarifies this statement:

Figure 1.21 – The most significant 64 bits of the 128-bit product of two 64-bit factors

For example:

long x = 234253490223L;
long y = -565951223449L;
long resultSigned = Math.multiplyHigh(x, y); // -7187

The returned result (-7187) is a signed value. The unsigned version of this method, unsignedMultiplyHigh(long x, long y), was introduced in JDK 18 and it works as follows:

// 234253483036
long resultUnsigned = Math.unsignedMultiplyHigh(x, y);

So, unsignedMultiplyHigh(long x, long y) returns a long representing the most significant 64 bits of the unsigned 128-bit product of two unsigned 64-bit factors.But, remember that Java supports unsigned arithmetic not unsigned values/variables. However, thanks to the Data Geekery company (very well known for the famous jOOQ), we have jOOU (Java Object Oriented Unsigned) project meant to bring unsigned number types in Java. While you can explore this project at https://github.com/jOOQ/jOOU, here is a sample of defining an unsigned long:

// using jOOU
ULong ux = ulong(234253490223L);  // 234253490223
ULong uy = ulong(-565951223449L); // 18446743507758328167

And, using it in unsignedMultiplyHigh(long x, long y):

long uResultUnsigned = Math.unsignedMultiplyHigh(
    ux.longValue(), uy.longValue());

You can find these examples in the bundled code.

Leave a Reply

Your email address will not be published. Required fields are marked *