Why Doesn't Java Support Unsigned Ints

Why doesn't Java support unsigned ints?

This is from an interview with Gosling and others, about simplicity:

Gosling: For me as a language designer, which I don't really count myself as these days, what "simple" really ended up meaning was could I expect J. Random Developer to hold the spec in his head. That definition says that, for instance, Java isn't -- and in fact a lot of these languages end up with a lot of corner cases, things that nobody really understands. Quiz any C developer about unsigned, and pretty soon you discover that almost no C developers actually understand what goes on with unsigned, what unsigned arithmetic is. Things like that made C complex. The language part of Java is, I think, pretty simple. The libraries you have to look up.

Declaring an unsigned int in Java

Java does not have a datatype for unsigned integers.

You can define a long instead of an int if you need to store large values.

You can also use a signed integer as if it were unsigned. The benefit of two's complement representation is that most operations (such as addition, subtraction, multiplication, and left shift) are identical on a binary level for signed and unsigned integers. A few operations (division, right shift, comparison, and casting), however, are different. As of Java SE 8, new methods in the Integer class allow you to fully use the int data type to perform unsigned arithmetic:

In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 2^32-1. Use the Integer class to use int data type as an unsigned integer. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.

Note that int variables are still signed when declared but unsigned arithmetic is now possible by using those methods in the Integer class.

Signed and unsigned data types in java

Java only supports signed types (except char) because it was assumed that one type was simpler for beginners to understand than having two types for each size. In C it was perceived to be a source of error so support for unsigned types was not included.

So the designers picked four sizes

  • byte, 8 bit
  • short, 16 bit
  • int, 32 bit
  • long, 64 bit.

and to keep things consistent they were all signed just like float and double However a signed byte is rarely very useful and given they allowed unsigned 16-bit char having an unsigned byte might have made more sense.

Where this doesn't work so well is when you have to interact with systems which use unsigned integer types. This can be source of confusion and to which type to use instead because often it doesn't make any difference. Java 8 will have operations to support unsigned types as well. These are added to the wrapper classes like Integer and Long

How to use the unsigned Integer in Java 8 and Java 9?

Per the documentation you posted, and this blog post - there's no difference when declaring the primitive between an unsigned int/long and a signed one. The "new support" is the addition of the static methods in the Integer and Long classes, e.g. Integer.divideUnsigned. If you're not using those methods, your "unsigned" long above 2^63-1 is just a plain old long with a negative value.

From a quick skim, it doesn't look like there's a way to declare integer constants in the range outside of +/- 2^31-1, or +/- 2^63-1 for longs. You would have to manually compute the negative value corresponding to your out-of-range positive value.

Why DataInput interface in Java doesn't have readUnsignedInt method

DataInput/DataOutput has a method for each of the primitives and String.

unsigned int is not a primitive but you can do the following since it was added.

long a = dis.readInt() & 0xFFFF_FFFFL;

dos.writeInt((int) a);

Why this interface doesn't have a readUnsignedInt method that would return long?

I assume the original designers didn't think you need one or they would have added an unsigned int type.

Is there any particular reason?

There is so many things you could add (and in my library I have added because I think they are useful) but the designers seemed to believe less is more.

Why doesn't Kotlin support unsigned integers?

Unsigned counterparts of Byte, Short, Int and Long do exist in Beta since Kotlin 1.3 and are stable as of Kotlin 1.5:

From the docs:

kotlin.UByte: an unsigned 8-bit integer, ranges from 0 to 255

kotlin.UShort: an unsigned 16-bit integer, ranges from 0 to 65535

kotlin.UInt: an unsigned 32-bit integer, ranges from 0 to 2^32 - 1

kotlin.ULong: an unsigned 64-bit integer, ranges from 0 to 2^64 - 1

Usage

// You can define unsigned types using literal suffixes
val uint = 42u

// You can convert signed types to unsigned and vice versa via stdlib extensions:
val int = uint.toInt()
val uint = int.toUInt()

Why doesn't .NET use unsigned integer types for things like DateTime.Month and DateTime.Year?

To quote "Language Independence and Language-Independent Components"

The .NET Framework is language independent. This means that, as a developer, you can develop in one of the many languages that target the .NET Framework, such as C#, C++/CLI, Eiffel, F#, IronPython, IronRuby, PowerBuilder, Visual Basic, Visual COBOL, and Windows PowerShell. You can access the types and members of class libraries developed for the .NET Framework without having to know the language in which they were originally written and without having to follow any of the original language's conventions. If you are a component developer, your component can be accessed by any .NET Framework app regardless of its language.

Not all languages support unsigned integers, so because of that using unsigned integers in public or protected methods makes your code non CLS compliant. You are allowed to use them on private and internal members, just not on public or protected ones. Because of this the .NET framework tries to make all of it's public methods and members CLS compliant so they can be used from any language.

Java8 unsigned arithmetic

If you're referring to

(Long.compareUnsigned(l, Long.MAX_VALUE*2) < 0)

l reaches

-9223372036854775808

unsigned it is

9223372036854775808

and

Long.MAX_VALUE*2

is

18446744073709551614

So l is smaller than Long.MAX_VALUE*2 in the unsigned world.

Assuming you're asking about the 0's

0
0
0
...
0

the problem (if you see it that way) is that, for long (other numerical primitives), the first bit is the sign bit.

so

10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

is

-9223372036854775808

When you do

-9223372036854775808 + -9223372036854775808

you underflow (overflow?) since

    10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+ 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

is

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

which is 0. On later loop iterations, 0 + 0 remains 0.

Is Java's lack of unsigned primitive types a characteristic of Java the platform or Java the language?

Java Bytecode Specification only defines signed types:

The integral types are byte, short, int, and long, whose values are
8-bit, 16-bit, 32-bit, and 64-bit signed two's-complement integers

But a language implemented on top of the JVM can probably add an unsigned type at the syntactic level and just handle the conversion at the compilation stage.



Related Topics



Leave a reply



Submit