Unsigned variables in Scala

后端 未结 2 693
逝去的感伤
逝去的感伤 2021-02-07 07:01

I am converting some C code to Scala as we are moving (allegedly) into the Modern world here in Corporate towers, or so I have been told anyways.

Some of the C code uses

相关标签:
2条回答
  • 2021-02-07 07:46

    The JVM unfortunately does not support unsigned data types (besides char, thanks Erwin), but there is hope! Scala has a sufficiently advanced type system that allows you to create your own types that act like unsigned types!

    There is even a library that already does it! The library overloads the operators and provides conversions.

    0 讨论(0)
  • 2021-02-07 07:50

    The only difference between signed an unsigned math in C and on the JVM comes up with the right-shift operator. For unsigned math, you use logical shift (since you don't want sign extension), whereas for signed math you do an arithmetic shift (which preserves the sign). This is one of the beauties of Two's complement arithmetic.

    Based on that, all you have to do is change the Java/Scala >> operator for the >>> operator, and you'll get the same answer, bit-by-bit. However, depending on what you're doing it might still be problematic when you try to do something with the result, e.g. if you want to print it as an unsigned integer.

    Let's say you want to do some math with "unsigned" longs in Scala and print the result at the end. Just use a normal long, use the >>> (logical shift) operator in place of >>, and then convert it to something else at the end that can represent the unsigned value. You could use a library like suggested in @rightfold's answer, or you can just do something simple like this:

    val x = Long.MaxValue // declare my "unsigned" long
    // do some math with it ...
    val y = x + 10
    
    // Convert it to the equivalent Scala BigInt
    def asUnsigned(unsignedLong: Long) =
      (BigInt(unsignedLong >>> 1) << 1) + (unsignedLong & 1)
    
    x
    // Long = 9223372036854775807
    asUnsigned(y)
    // res1: scala.math.BigInt = 9223372036854775817
    

    If you're just using Ints, then you don't even have to convert to BigInt at the end since a Long can hold the answer. Just use the method that @BrianRoach suggests in his comment above to convert an Int's "unsigned" value to the equivalent Long by masking-off the higher-order bytes. However, again, you shouldn't do the conversion until you absolutely have to. Even when using a 64-bit JVM on a 64-bit processor, the integer multiply and divide operations will be slower for a Long (64-bit) than for an Int (32-bit). (See this question for more details: Are 64 bit integers less efficient than 32 bit integers in the JVM?).

    0 讨论(0)
提交回复
热议问题