Подтвердить что ты не робот

Неподписанные переменные в Scala

Я конвертирую некоторый код С в Scala, когда мы двигаемся (предположительно) в Современный мир здесь, в Корпоративные башни, или так мне все равно сказали.

В некотором коде C используются неподписанные переменные, которые выполняют значительное количество выполняемых над ними операций с уровнем бит (сдвигом).

Я в полной мере останавливаюсь на том, как их преобразовать в Scala, учитывая, что я верю как Scala (и Java), так и JVM находят неподписанные типы.

Любые советы приветствуются.

4b9b3361

Ответ 1

Единственное различие между подписанной математикой без знака в C и JVM возникает с помощью оператора смены вправо. Для неподписанной математики вы используете логический сдвиг (поскольку вы не хотите расширения знака), тогда как для подписанной математики вы выполняете арифметический сдвиг (который сохраняет знак). Это одна из красавиц Арифметика двух дополнений.

Исходя из этого, все, что вам нужно сделать, это изменить оператор Java/ Scala >> для оператора >>>, и вы получите один и тот же ответ, по-разному. Однако, в зависимости от того, что вы делаете, все может быть проблематично, когда вы пытаетесь что-то сделать с результатом, например. если вы хотите напечатать его как целое без знака.

Скажем, вы хотите сделать математику с "unsigned" longs в Scala и напечатать результат в конце. Просто используйте обычный длинный, используйте >>> (логический сдвиг) вместо >>, а затем преобразуйте его в нечто другое в конце, которое может представлять значение без знака. Вы можете использовать библиотеку, например, предложенную в ответе @rightfold, или вы можете просто сделать что-то простое:

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

Если вы просто используете Int s, вам даже не нужно преобразовывать в BigInt в конце, так как Long может удерживать ответ. Просто используйте метод, который @BrianRoach предлагает в своем комментарии выше для преобразования значения Int "unsigned" в эквивалентный Long путем маскировки байтов более высокого порядка. Однако, опять же, вы не должны делать конверсию, пока не будете абсолютно необходимы. Даже при использовании 64-разрядной JVM на 64-битном процессоре операции умножения и деления целого числа будут медленнее для Long (64-разрядной), чем для Int (32-разрядной). (См. Этот вопрос для получения дополнительной информации: Имеют ли 64-битные целые числа менее эффективные, чем 32-битные целые числа в JVM?).

Ответ 2

JVM, к сожалению, не поддерживает неподписанные типы данных (кроме char, спасибо Erwin), но есть надежда! Scala имеет достаточно продвинутую систему типов, которая позволяет создавать собственные типы, которые действуют как неподписанные типы!

Существует даже библиотека, которая уже делает это! Библиотека перегружает операторы и обеспечивает конверсии.