4

Is there a way in Java to use unsigned numbers like in (My)SQL?

For example: I want to use an 8-bit variable (byte) with a range like: 0 ... 256; instead of -128 ... 127.

Eiko
  • 25,601
  • 15
  • 56
  • 71
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287

7 Answers7

10

No, Java doesn't have any unsigned primitive types apart from char (which has values 0-65535, effectively). It's a pain (particularly for byte), but that's the way it is.

Usually you either stick with the same size, and overflow into negatives for the "high" numbers, or use the wider type (e.g. short for byte) and cope with the extra memory requirements.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • You sure that it actually saves you memory? I don't think it does--I think Java uses whatever your word size is to hold a byte (Except in arrays, which it will pack). In either case, you're taking a little speed hit not to use ints though. – Bill K Oct 09 '09 at 16:43
  • Partial support now in Java 8 for unsigned arithmetic. See http://stackoverflow.com/questions/25556017/how-to-use-the-unsigned-integer-in-java-8 – rghome May 05 '15 at 11:49
3

You can use a class to simulate an unsigned number. For example

public class UInt8 implements Comparable<UInt8>,Serializable
   {
   public static final short MAX_VALUE=255;
   public static final short MIN_VALUE=0;
   private short storage;//internal storage in a int 16

   public UInt8(short value)
      {
      if(value<MIN_VALUE || value>MAX_VALUE) throw new IllegalArgumentException();
      this.storage=value;
      }

   public byte toByte()
      {
      //play with the shift operator ! << 
      }
  //etc...
   }
Pierre
  • 34,472
  • 31
  • 113
  • 192
  • 2
    That is possible. But if I want a unsigned var, it's for the memory-size. If not, I can use an int. – Martijn Courteaux Oct 08 '09 at 19:54
  • 2
    The overhead of an object instance (memory needed for things other than its visible fields) varies by JVM, but it typically around 40 bytes. 4000% overhead... well, probably not worth saving a few '& 0xFF' operations. – erickson Oct 08 '09 at 19:58
  • 1
    Eric & Martin, 100% agree. But it can be useful if you want to be sure that your code is dealing with the correct type of data. For example when your code is reading/writing a binary structure that is used by a C program. – Pierre Oct 08 '09 at 20:05
2

You can mostly use signed numbers as if they were unsigned. Most operations stay the same, some need to be modified. See this post.

Community
  • 1
  • 1
starblue
  • 55,348
  • 14
  • 97
  • 151
2

Internally, you shouldn't be using the smaller values--just use int. As I understand it, using smaller units does nothing but slow things down. It doesn't save memory because internally Java uses the system's word size for all storage (it won't pack words).

However if you use a smaller size storage unit, it has to mask them or range check or something for every operation.

ever notice that char (any operation) char yields an int? They just really don't expect you to use these other types.

The exceptions are arrays (which I believe will get packed) and I/O where you might find using a smaller type useful... but masking will work as well.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • +1 for explaining why using an unsigned would not achieve any space saving ... which is apparently what the OP is trying to do. – Stephen C Oct 09 '09 at 01:40
  • @Stephen: concerns about space are certainly about arrays unless OP is utterly clueless. Anyway, what type would you use for a large array of byte-size samples? I suppose you can use bytes and just mask them with 255, but this issue is a major flaw in Java. – R.. GitHub STOP HELPING ICE Oct 09 '10 at 09:40
1

Nope, you can't change that. If you need something larger than 127 choose something larger than a byte.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
0

If you need to optimize your storage (e.g. large matrix) you can u can code bigger positive numbers with negatives numbers, so to save space. Then, you have to shift the number value to get the actual value when needed. For instance, I want to manipulate short positive numbers only. Here how this is possible in Java:

        short n = 32767;
        n = (short) (n + 10);
        System.out.println(n);     
        int m = (int) (n>=0?n:n+65536); 
        System.out.println(m);

So when a short integer exceeds range, it becomes negative. Yet, at least you can store this number in 16 bits, and restore its correct value by adding shift value (number of different values that can be coded). The value should be restored in a larger type (int in our case). This may not be very convenient, but I find it's so in my case.

hmitcs
  • 343
  • 4
  • 11
0

I'm quite new to Java and to programming. Yet, I encountered the same situation recently the need of unsigned values.

It took me around two weeks to code everything I had in mind, but I'm a total noob, so you could spend much less.

The general idea is to create interface, I have named it: UnsignedNumber<Base, Shifted> and to extend Number.class whilst implementing an abstract AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>> class.

So, Base parameterized type represents the base type, Shifted represents actual Java type. Impl is a shortcut for Implementation of this abstract class.

Most of the time consumed boilerplate of Java 8 Lambdas and internal private classes and safety procedures. The important thing was to achieve the behavior of unsigned when mathematical operation like subtraction or negative addition spawns the zero limit: to overflow the upper signed limit backwards.

Finally, it took another couple of days to code factories and implementation sub classes.

So far I have know: UByte and MUByte UShort and MUShort UInt and MUInt ... Etc.

They are descendants of AbstractUnsigned: UByte or MUByte extend AbstractUnsigned<Byte, Short, UByte> or AbstractUnsigned<Byte, Short, MUByte> UShort or MUShort extend AbstractUnsigned<Short, Integer, UShort> or AbstractUnsigned<Short, Integer, MUShort> ...etc.

The general idea is to take unsigned upper limit as shifted (casted) type and code transposition of negative values as they were to come not from zero, but the unsigned upper limit.

UPDATE: (Thanks to Ajeans kind and polite directions)

/**
* Adds value to the current number and returns either
* new or this {@linkplain UnsignedNumber} instance based on
* {@linkplain #isImmutable()}
*
* @param value value to add to the current value
* @return new or same instance
* @see #isImmutable()
*/
public Impl plus(N value) {
    return updater(number.plus(convert(value)));
}

This is an externally accessible method of AbstractUnsigned<N, Shifted, Impl> (or as it was said before AbstractUnsigned<Base, Shifted, Impl>); Now, to the under-the-hood work:

private Impl updater(Shifted invalidated){
    if(mutable){
        number.setShifted(invalidated);
        return caster.apply(this);
    } else {
        return shiftedConstructor.apply(invalidated);
    }
}

In the above private method mutable is a private final boolean of an AbstractUnsigned. number is one of the internal private classes which takes care of transforming Base to Shifted and vice versa. What matters in correspondence with previous 'what I did last summer part' is two internal objects: caster and shiftedConstructor:

final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;

These are the parameterized functions to cast N (or Base) to Shifted or to create a new Impl instance if current implementation instance of the AbstractUnsigned<> is immutable.

Shifted plus(Shifted value){
    return spawnBelowZero.apply(summing.apply(shifted, value));
}

In this fragment is shown the adding method of the number object. The idea was to always use Shifted internally, because it is uncertain when the positive limits of 'original' type will be spawned. shifted is an internal parameterized field which bears the value of the whole AbstractUnsigned<>. The other two Function<> derivative objects are given below:

final private BinaryOperator<Shifted> summing;
final private UnaryOperator<Shifted> spawnBelowZero;

The former performs addition of two Shifted values. And the latter performs spawning below zero transposition.

And now an example from one of the factory boilerplates 'hell' for AbstractUnsigned<Byte, Short> specifically for the mentioned before spawnBelowZero UnaryOperator<Shifted>:

...,
         v-> v >= 0
         ? v
         : (short) (Math.abs(Byte.MIN_VALUE) + Byte.MAX_VALUE + 2 + v),
...

if Shifted v is positive nothing really happens and the original value is being returned. Otherwise: there's a need to calculate the upper limit of the Base type which is Byte and add up to that value negative v. If, let's say, v == -8 then Math.abs(Byte.MIN_VALUE) will produce 128 and Byte.MAX_VALUE will produce 127 which gives 255 + 1 to get the original upper limit which was cut of by the sign bit, as I got that, and the so desirable 256 is in the place. But the very first negative value is actually that 256 that's why +1 again or +2 in total. Finally, 255 + 2 + v which is -8 gives 255 + 2 + (-8) and 249

Or in a more visual way:

0 1 2 3 ... 245 246 247 248 249 250 251 252 253 254 255 256
                             -8  -7  -6  -5  -4  -3  -2  -1

And to finalize all that: this definitely does not ease your work or saves memory bytes, but you have a pretty much desirable behaviour when it is needed. And you can use that behaviour pretty much with any other Number.class subclasses. AbstractUnsigned being subclass of Number.class itself provides all the convenience methods and constants similar to other 'native' Number.class subclasses, including MIN_VALUE and MAX_VALUE and a lot more, for example, I coded convenience method for mutable subclasses called makeDivisibileBy(Number n) which performs the simplest operation of value - (value % n).

My initial endeavour here was to show that even a noob, such as I am, can code it. My initial endeavour when I was coding that class was to get conveniently versatile tool for constant using.

Community
  • 1
  • 1
Denis Volin
  • 206
  • 1
  • 8
  • This reads like a "what I did last summer", so any answer contained therein is very difficult to find. I suggest removing everything extraneous, such as "it took me two weeks" etc. Also, it would be much more useful to not only explain *what* you have done, but also *how*, and how this adds **new information** to this ancient question. – Ajean Jan 04 '16 at 23:45