2009-10-08 7 views
4

Есть ли способ в Java использовать неподписанные числа, как в (My) SQL?Java: Unsigned numbers

Например: Я хочу использовать 8-битную переменную (byte) с диапазоном: 0 ... 256; вместо -128 ... 127.

ответ

9

Нет, Java не имеет каких-либо неподписанных примитивных типов, кроме char (который имеет значения 0-65535, эффективно). Это боль (особенно для byte), но так оно и есть.

Обычно вы либо придерживаетесь одинакового размера, либо переполняете негативы для «высоких» чисел или используете более широкий тип (например, short для byte) и справляетесь с дополнительными требованиями к памяти.

+0

Вы уверены, что это действительно экономит память? Я не думаю, что это так. Я думаю, что Java использует любой размер вашего слова для хранения байта (кроме массивов, которые он будет упаковывать). В любом случае, вы делаете небольшую скорость, чтобы не использовать ints. –

+0

Частичная поддержка теперь в Java 8 для беззнаковой арифметики. См. Http://stackoverflow.com/questions/25556017/how-to-use-the-unsigned-integer-in-java-8 – rghome

1

Нет, вы не можете изменить это. Если вам нужно что-то большее 127, выберите что-то большее, чем байт.

3

Вы можете использовать класс для имитации числа без знака. Например,

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... 
    } 
+2

Это возможно. Но если я хочу unsigned var, это размер памяти. Если нет, я могу использовать int. –

+2

Накладные расходы на экземпляр объекта (память, необходимая для вещей, отличных от его видимых полей) зависит от JVM, но обычно около 40 байт. 4000% накладных расходов ... ну, вероятно, не стоит экономить несколько операций «& 0xFF». – erickson

+1

Eric & Martin, 100% согласен. Но это может быть полезно, если вы хотите быть уверены, что ваш код имеет дело с правильным типом данных. Например, когда ваш код читает/записывает двоичную структуру, которая используется программой C. – Pierre

2

В основном вы можете использовать подписанные числа, как если бы они были без знака. Большинство операций остаются неизменными, некоторые из них необходимо изменить. См. this post.

2

Внутренне вы не должны использовать меньшие значения - просто используйте int. Насколько я понимаю, использование меньших единиц не делает ничего, кроме замедления. Он не сохраняет память, потому что внутренне Java использует размер слова системы для всего хранилища (он не будет упаковывать слова).

Однако, если вы используете блок хранения меньшего размера, он должен замаскировать их или проверить диапазон или что-то для каждой операции.

когда-либо заметили, что char (любая операция) char дает int? Они просто не ожидали, что вы будете использовать эти другие типы.

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

+0

+1 для объяснения, почему использование unsigned не обеспечило бы экономии пространства ... что, по-видимому, пытается сделать OP. –

+0

@ Stephen: проблемы с пространством, безусловно, касаются массивов, если OP не совсем невежествен. В любом случае, какой тип вы бы использовали для большого массива байтов? Я полагаю, вы можете использовать байты и просто маскировать их с 255, но эта проблема является основным недостатком Java. –

0

Если вам нужно оптимизировать ваше хранилище (например, большую матрицу), вы можете запрограммировать большее число положительных чисел с номерами негативов, чтобы сэкономить место. Затем вам нужно сдвинуть числовое значение, чтобы получить фактическое значение, когда это необходимо. Например, я хочу использовать только короткие положительные числа. Здесь, как это возможно в Java:

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

Поэтому, когда короткое целое число превышает диапазон, оно становится отрицательным. Тем не менее, по крайней мере, вы можете сохранить это число в 16 бит и восстановить его правильное значение, добавив значение сдвига (количество различных значений, которые могут быть закодированы). Значение должно быть восстановлено в более крупном типе (int в нашем случае). Это может быть не очень удобно, но я считаю, что это так в моем случае.

0

Я новичок в Java и программировании. Тем не менее, я недавно столкнулся с такой же ситуацией, когда нуждался в значениях без знака.

Мне потребовалось около двух недель, чтобы закодировать все, что я имел в виду, но я полный noob, так что вы могли бы потратить гораздо меньше.

Общая идея - создать интерфейс, я назвал его: UnsignedNumber<Base, Shifted> и расширить Number.class при реализации абстрактного класса AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>>.

Итак, базовый параметризованный тип представляет базовый тип, Shifted представляет собой действительный тип Java. Impl - это ярлык для реализации этого абстрактного класса.

Большая часть потребляемого шаблона Java 8 Lambdas и внутренних частных классов и процедур безопасности. Важно было добиться поведения без знака, когда математическая операция, например вычитание или отрицательное сложение, порождает нулевой предел: переполнение верхнего подписанного предела назад.

Наконец, потребовалось еще несколько дней, чтобы закодировать фабрики и подклассы реализации.

До сих пор я знаю: UBYTE и MUByte UShort и MUShort UInt и MUInt ... и т.д.

Они являются потомками AbstractUnsigned: UBYTE или MUByte продлить AbstractUnsigned<Byte, Short, UByte> или AbstractUnsigned<Byte, Short, MUByte> UShort или MUShort удлинение AbstractUnsigned<Short, Integer, UShort> или AbstractUnsigned<Short, Integer, MUShort> ... и т.п.

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

ОБНОВЛЕНИЕ: (Благодаря Ajeans и вежливы направлениях)

/** 
* 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))); 
} 

Это внешний доступный метод AbstractUnsigned<N, Shifted, Impl> (или, как это было сказано ранее AbstractUnsigned<Base, Shifted, Impl>); Теперь, в соответствии с капотом работы:

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

В приведенном выше частном методе mutable является private final boolean из AbstractUnsigned. number является одним из внутренних частных классов, который заботится о преобразовании Base в Shifted и наоборот. Какие вопросы в соответствии с предыдущими «что я сделал прошлым летом часть» есть два внутренних объектов: caster и shiftedConstructor:

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

Это параметризованные функции для литых N (или Base) для Shifted или к создайте новый экземпляр Impl, если текущий экземпляр реализации AbstractUnsigned<> является неизменным.

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

В этом фрагменте показан при добавлении метод number объекта. Идея заключалась в том, чтобы всегда использовать Shifted внутренне, потому что неясно, когда появятся положительные пределы «оригинального» типа. shifted - внутреннее параметризованное поле, которое несет значение всего AbstractUnsigned<>. Два других Function<> производных объектов приведены ниже:

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

Первый выполняет сложение двух Shifted значений. И последний выполняет нерестилище ниже нулевой транспозиции.

А теперь пример из одного завода Макеты «ад» для AbstractUnsigned<Byte, Short> специально для упоминалось ранее spawnBelowZeroUnaryOperator<Shifted>:

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

если Shifted v не положителен ничего на самом деле происходит, и исходное значение возвращается. В противном случае: необходимо рассчитать верхний предел Base, который равен Byte, и добавить к нему отрицательное значение v. Если, скажем, v == -8 тогда Math.abs(Byte.MIN_VALUE) будет производить 128 и Byte.MAX_VALUE будет производить 127, что дает 255 + 1, чтобы получить оригинальный верхний предел, который был вырезан из долота знака, как я получил это, и так хочется 256 находится в месте , Но самое первое отрицательное значение - Фактически это 256 вот почему +1 снова или +2 всего. Наконец, 255 + 2 + v который -8 дает 255 + 2 + (-8) и 249

Или в более наглядном виде:

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

и завершить все, что: это определенно не облегчит вашу работу или сохраняет байт памяти, но у вас есть очень желательно, когда это необходимо. И вы можете использовать это поведение в значительной степени с любыми другими подклассами Number.class. AbstractUnsigned быть подклассом самого Number.class предоставляет все удобные методы и константы подобно другим «родным» Number.class подклассов, в том числе MIN_VALUE и MAX_VALUE и многое другое, к примеру, я закодированы удобный метод для изменяемых подклассов называется makeDivisibileBy(Number n), который выполняет самую простую работу value - (value % n).

Мои первоначальные усилия заключались в том, чтобы показать, что даже нуб, такой как я, может его закодировать. Моя первоначальная работа, когда я кодировал этот класс, заключался в том, чтобы получить удобный универсальный инструмент для постоянного использования.

+0

Это читается как «то, что я сделал прошлым летом», поэтому любой содержащийся в нем ответ очень трудно найти. Я предлагаю удалить все постороннее, например, «мне потребовались две недели» и т. Д. Кроме того, было бы гораздо полезнее не только объяснить, что вы сделали, но и * как *, и как это добавляет ** новую информацию ** к этому древнему вопросу. – Ajean

+0

Исправлено немного =) –