Почему в Java нет поддержки целых чисел без знака?
Мне кажется странным упущением, учитывая, что они позволяют писать код, который с меньшей вероятностью приведет к переполнению при неожиданно большом вводе.
Кроме того, использование целых чисел без знака может быть формой самодокументирования, поскольку они указывают, что значение, которое должно было содержать целое число без знака, никогда не должно быть отрицательным.
Наконец, в некоторых случаях целые числа без знака могут быть более эффективными для определенных операций, таких как деление.
В чем недостаток включения этих?
java
language-design
unsigned
integer
dsimcha
источник
источник
byte
не могут дать ровный140
уровень серого, но-116
который вам необходим,& 0xff
чтобы получить правильное значение.Ответы:
Это из интервью с Гослингом и другими , о простоте:
источник
Читая между строк, я думаю, что логика была примерно такая:
В основном, я бы сказал, что это было разумное решение. Возможно, я бы имел:
Тем не менее, с небольшим количеством хитрости, операции с беззнаковыми значениями до 32 бит не так уж плохи, и большинству людей не нужно 64-разрядное деление без знака или сравнение.
источник
short
это используется - алгоритмы defltate / gzip / inflate являются 16-битными, и они сильно зависят от коротких замыканий ... или, по крайней мере,short[]
[по общему признанию, они являются нативными - хотя java-имплантат алгоритма несет террабайты данных]. Последний (short[]
) имеет значительное преимущество,int[]
поскольку он занимает вдвое меньше памяти и меньше памяти = лучшие свойства кэширования, намного лучшая производительность.Это более старый вопрос, и Пэт кратко упомянул char, я просто подумал, что я должен расширить это для других, которые будут смотреть на это в будущем. Давайте подробнее рассмотрим примитивные типы Java:
byte
- 8-разрядное целое число со знакомshort
- 16-разрядное целое число со знакомint
- 32-разрядное целое число со знакомlong
- 64-разрядное целое число со знакомchar
- 16-битный символ (целое число без знака)Хотя
char
не поддерживаетunsigned
арифметику, по сути, она может рассматриваться какunsigned
целое число. Вы должны были бы явно привести арифметические операции обратноchar
, но это дает вам возможность указатьunsigned
числа.Да, нет прямой поддержки целых чисел без знака (очевидно, мне не пришлось бы преобразовывать большинство моих операций обратно в char, если бы была прямая поддержка). Тем не менее, безусловно, существует неподписанный примитивный тип данных. Я хотел бы также видеть неподписанный байт, но я полагаю, что удвоение стоимости памяти и использование char - приемлемый вариант.
редактировать
С JDK8 есть новый API - интерфейсы для
Long
иInteger
которые обеспечивают вспомогательные методы при леченииlong
иint
значение как беззнаковые значения.compareUnsigned
divideUnsigned
parseUnsignedInt
parseUnsignedLong
remainderUnsigned
toUnsignedLong
toUnsignedString
Кроме того, Guava предоставляет несколько вспомогательных методов для выполнения аналогичных действий с целочисленными типами, что помогает сократить разрыв, оставленный отсутствием встроенной поддержки
unsigned
целых чисел.источник
char
он слишком мал, чтобы поддерживатьlong
арифметику, например.В Java есть типы без знака или, по крайней мере, один: char - это беззнаковое сокращение. Так что, что бы ни извинял Гослинг, на самом деле это просто его невежество, почему нет других неподписанных типов.
Также короткие типы: шорты все время используются для мультимедиа. Причина в том, что вы можете разместить 2 сэмпла в одном 32-битном беззнаковом коде и векторизовать множество операций. То же самое с 8-битными данными и беззнаковым байтом. Вы можете поместить 4 или 8 образцов в регистр для векторизации.
источник
char
для всего, кроме персонажей.Как только подписанные и неподписанные целые числа смешиваются в выражении, вещи начинают запутываться, и вы, вероятно , потеряете информацию. Ограничение Java подписанными целыми числами только действительно проясняет ситуацию. Я рад, что мне не нужно беспокоиться обо всем бизнесе со знаком / без знака, хотя иногда я пропускаю 8-й бит в байте.
источник
static_cast
много вокруг, чтобы смешать их. Это действительно грязно.byte
быть подписана, как это было в Паскале.& 0xFF
каждом продвижении между байтами и кодом код становится еще сложнее.http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html
Этот парень говорит, потому что стандарт C определяет операции, включающие неподписанные и подписанные целые, которые должны рассматриваться как неподписанные. Это может привести к тому, что целые числа с отрицательными знаками развернутся в большое целое число без знака, что может привести к ошибкам.
источник
-1
- с любым беззнаковым числом - даже с нулем.-1
«неизвестный» возраст (как предполагает статья) - один из классических примеров «запаха кода» . Например, если вы хотите вычислить «насколько Алиса старше Боба?», А A = 25 и B = -1, вы получите ответ,±26
который просто неверен. Правильная обработка неизвестных значений является своим родом ,Option<TArg>
когдаSome(25) - None
вернемся быNone
.Я думаю, что с Java все в порядке, добавление unsigned усложнит ее без особой выгоды. Даже с упрощенной целочисленной моделью большинство программистов на Java не знают, как ведут себя базовые числовые типы - просто прочитайте книгу Java Puzzlers, чтобы увидеть, какие заблуждения вы можете иметь.
Что касается практических советов:
Если ваши значения имеют произвольный размер и не вписываются
int
, используйтеlong
. Если они не подходят дляlong
использованияBigInteger
.Используйте меньшие типы только для массивов, когда вам нужно сэкономить место.
Если вам нужно ровно 64/32/16/8 бит, используйте
long
/int
/short
/byte
и перестаньте беспокоиться о знаковом бите, за исключением деления, сравнения, сдвига вправо и приведения.Смотрите также этот ответ о "переносе генератора случайных чисел с C на Java".
источник
>>
и>>>
для подписанного и без знака, соответственно. Сдвиг влево не проблема.>>>
не работает дляshort
иbyte
. Например,(byte)0xff>>>1
урожайность,0x7fffffff
а не0x7f
. Другой пример:byte b=(byte)0xff; b>>>=1;
приведет кb==(byte)0xff
. Конечно, вы можете сделать,b=(byte)(b & 0xff >> 1);
но это добавляет еще одну операцию (поразрядно &).С JDK8 у него есть некоторая поддержка для них.
Мы все еще можем увидеть полную поддержку неподписанных типов в Java, несмотря на озабоченность Гослинга.
источник
Я знаю, что этот пост слишком старый; однако для вашего интереса в Java 8 и более поздних версиях вы можете использовать
int
тип данных для представления 32-разрядного целого числа без знака, которое имеет минимальное значение 0 и максимальное значение 2 32 -1. ИспользуйтеInteger
класс, чтобы использоватьint
тип данных как целое число без знака, и в класс были добавлены статические методы, подобныеcompareUnsigned()
иdivideUnsigned()
т. Д.,Integer
Для поддержки арифметических операций для целых чисел без знака.источник
Я слышал истории о том, что они должны были быть включены в оригинальную версию Java. Дуб был предшественником Java, и в некоторых спецификациях упоминалось о присвоенных значениях. К сожалению, они никогда не превращались в язык Java. Насколько кому-то удалось выяснить, что они просто не были реализованы, вероятно, из-за нехватки времени.
источник
char
) были опущены, потому что дизайнеры думали, что они были плохой идеей ... учитывая цели языка.Однажды я проходил курс C ++ с кем-то из комитета по стандартам C ++, который подразумевал, что Java приняла правильное решение, чтобы избежать использования целых чисел без знака, потому что (1) большинство программ, которые используют целые числа без знака, могут так же хорошо справляться с целыми числами со знаком, и это более естественно в С точки зрения того, как люди думают, и (2) использование целых чисел без знака приводит к простоте создания, но трудностям для отладки, таким как целочисленное арифметическое переполнение и потеря значительных битов при преобразовании между типами со знаком и без знака. Если вы по ошибке вычитаете 1 из 0 с помощью целых чисел со знаком, это часто приводит к сбою вашей программы и облегчает поиск ошибки, а не к 2 ^ 32 - 1, а компиляторы и инструменты статического анализа и проверки времени выполнения должны Предположим, вы знаете, что делаете, так как решили использовать беззнаковую арифметику. Также,
Давным-давно, когда память была ограничена, а процессоры не работали автоматически на 64 битах сразу, каждый бит учитывался намного больше, так что подписывание против неподписанных байтов или шорт действительно имело гораздо большее значение и, очевидно, было правильным решением при разработке. Сегодня просто использовать подписанное int более чем достаточно почти во всех случаях обычного программирования, и если вашей программе действительно нужно использовать значения больше 2 ^ 31 - 1, вам все равно часто просто требуется long. Как только вы перешли на территорию использования длинных, еще сложнее найти причину, по которой вы действительно не можете обойтись с 2 ^ 63 - 1 положительным целым числом. Всякий раз, когда мы перейдем на 128-битные процессоры, это будет еще меньше проблем.
источник
Ваш вопрос «Почему Java не поддерживает беззнаковые целые»?
И мой ответ на ваш вопрос заключается в том, что Java хочет, чтобы все ее примитивные типы: byte , char , short , int и long обрабатывались как байты , word , dword и qword соответственно, точно так же, как в сборке, а операторы Java подписаны операции на всех его примитивных типах, кроме char , но только на char они только 16-битные без знака.
Таким образом, статические методы предполагают, что они являются операциями без знака также для 32- и 64-разрядных.
Вам нужен последний класс, чьи статические методы могут быть вызваны для операций без знака .
Вы можете создать этот последний класс, назвать его как угодно и реализовать его статические методы.
Если вы не знаете, как реализовать статические методы, эта ссылка может вам помочь.
На мой взгляд, Java это не похоже на C ++ вообще , если он ни не поддерживает беззнаковые типы , ни перегрузку операторов, поэтому я думаю , что Java следует рассматривать как совершенно другой язык как от C ++ и от C.
Между прочим, в названии языков оно также совершенно иное.
Поэтому я не рекомендую в Java набирать код, похожий на C, и вообще не рекомендую набирать код, похожий на C ++, потому что тогда в Java вы не сможете делать то, что хотите делать дальше в C ++, т. е. код не будет по-прежнему похож на C ++, и для меня это плохо - кодировать так, менять стиль посередине.
Я рекомендую писать и использовать статические методы также для подписанных операций, поэтому вы не увидите в коде смеси операторов и статических методов для подписанных и неподписанных операций, если только вам не нужны только подписанные операции в коде, и это нормально используйте только операторы.
Кроме того, я рекомендую не использовать короткие , Int и длинные примитивные типы, а также использовать слово , двойное слово и QWORD соответственно вместо этого, и вы об вызвать статические методы для неподписанных операций и / или подписаны операции вместо использования операторов.
Если вы собираетесь выполнять только подписанные операции и использовать операторы только в коде, тогда можно использовать эти примитивные типы short , int и long .
На самом деле слово , двойное слово и QWORD ничего не существует в языке, но вы можете создать новый класс для всех и реализация каждого должно быть очень легко:
Слово класса содержит только примитивный тип short , класс dword содержит только примитивный тип int, а класс qword содержит только примитивный тип long . Теперь все неподписанные и подписанные методы как статические или нет по вашему выбору, вы можете реализовать в каждом классе, то есть все 16-битные операции, как без знака, так и со знаком, давая значения имен в классе слова , все 32-битные операции как без знака, так и подписывается, давая значащие имена в классе dword, и все 64-битные операции как без знака, так и подписывается, давая значащие имена в классе qword .
Если вам не нравится давать слишком много разных имен для каждого метода, вы всегда можете использовать перегрузку в Java, хорошо читать, что Java тоже не удаляла это!
Если вам нужны методы, а не операторы для 8-битных операций со знаком и методы для 8-битных операций без знака, у которых вообще нет операторов, то вы можете создать класс Byte (обратите внимание, что первая буква «B» - это заглавная, так что это не примитивный тип byte ) и реализует методы этого класса.
О передаче по значению и передаче по ссылке:
Если я не ошибаюсь, как в C #, примитивные объекты передаются по значению естественным образом, но объекты класса передаются по ссылке естественным образом, что означает, что объекты типа Byte , word , dword и qword будут передаваться по ссылке, а не по значению по умолчанию. Я хочу Java имела STRUCT объектов в C # есть, так что все Byte , слово , двойное слово и QWORD могут быть реализованы как структура вместо классапоэтому по умолчанию они передаются по значению, а не по ссылке по умолчанию, как любой объект структуры в C #, как и примитивные типы, передаются по значению, а не по ссылке по умолчанию, а потому что Java хуже, чем C #, и мы имеем чтобы справиться с этим, то есть только классы и интерфейсы, которые передаются по ссылке, а не по значению по умолчанию. Поэтому, если вы хотите передать объекты Byte , word , dword и qword по значению, а не по ссылке, как любой другой объект класса в Java, а также в C #, вам придется просто использовать конструктор копирования и все.
Это единственное решение, о котором я могу думать. Я просто хотел бы, чтобы я мог просто определить тип примитива для word, dword и qword, но Java не поддерживает typedef и не использует вообще, в отличие от C #, который поддерживает использование , что эквивалентно typedef в C.
О выходе:
Для одной и той же последовательности битов вы можете печатать их разными способами: в двоичном, десятичном (например, значение% u в C printf), в восьмеричном (например, значение% o в C printf), в шестнадцатеричном (например, значение% x в C printf) и как целое число (например, значение% d в C printf).
Обратите внимание, что C printf не знает тип переменных, передаваемых в качестве параметров функции, поэтому printf знает тип каждой переменной только из объекта char *, переданного первому параметру функции.
Таким образом, в каждом из классов: Byte , word , dword и qword вы можете реализовать метод print и получить функциональность printf, даже если примитивный тип класса подписан, вы все равно можете напечатать его как unsigned, следуя некоторому алгоритму, включающему логические и сдвиговые операции для получения цифр для вывода на выход.
К сожалению, ссылка, которую я вам дал, не показывает, как реализовать эти методы печати, но я уверен, что вы можете поискать алгоритмы, необходимые для реализации этих методов печати.
Это все, что я могу ответить на ваш вопрос и предложить вам.
источник
Потому что
unsigned
тип это чистое зло.Тот факт, что в Си
unsigned - int
производитunsigned
еще больше зла.Вот снимок проблемы, которая сожгла меня не раз:
Вы уже заметили ошибку? Признаюсь, я видел это только после того, как вошел с отладчиком.
Поскольку
n
это тип без знака,size_t
все выражениеn - (rays.size() - 1) / 2
оценивается какunsigned
. Это выражение предназначено быть подписано положениемn
го луча от среднего одном: первый луч от средних один на левой стороне будет иметь положение -1, то первый один справа будет иметь позицию +1 и т.д. После взяв значение abs и умножив наdelta
угол, я получу угол междуn
средним и третьим лучом.К сожалению для меня вышеупомянутое выражение содержало зло без знака и вместо оценки, скажем, -1, оно оценивалось как 2 ^ 32-1. Последующее преобразование в
double
запечатанную ошибку.После одного или двух ошибок, вызванных неправильным использованием
unsigned
арифметики, нужно задуматься, стоит ли получить дополнительный бит, который стоит дополнительных проблем. Я стараюсь, насколько это возможно, избегать любого использованияunsigned
типов в арифметике, хотя все еще использую его для неарифметических операций, таких как двоичные маски.источник
unsigned
конвертируетсяint
в чем пользаunsigned
? Он не будет иметь никакой функциональности, отличимой отshort
. И если вы преобразуетеint
только в смешанные операции, такие какunsigned+int
илиunsigned+float
, то у вас все еще остается проблема((unsigned)25-(unsigned)30)*1.0 > 0
, которая является основной причинойunsigned
ошибок, связанных с.exit(1);
действительно «стоить дополнительных проблем»? Разве невозможность открывать большие файлы действительно стоит безопасности, которую не испортят менее опытные Java-программистыunsigned
?n - (rays.size() - 1) / 2
. Вы должны всегда заключать в скобки бинарные операторы, потому что читатель кода не должен предполагать что-либо о порядке операций в компьютерной программе. То, что мы обычно говорим, что a + b c = a + (b c), не означает, что вы можете предположить это при чтении кода. Кроме того, вычисление должно быть определено вне цикла, чтобы его можно было проверить без наличия цикла. Это ошибка в том, что ваши типы не совпадают, а не в целых числах без знака. В C вы должны убедиться, что ваши типы выстраиваются в линию.В спецификации «C» есть несколько драгоценных камней, которые Java отбросила по прагматическим причинам, но которые постепенно возвращаются к спросу разработчиков (замыкания и т. Д.).
Я упоминаю первый, потому что это связано с этим обсуждением; соответствие значений указателя целочисленной арифметике без знака. И, что касается этой темы, трудность поддержания семантики без знака в мире Java со знаком.
Я бы предположил, что если бы кто-то получил альтернативное эго Денниса Ричи, чтобы посоветовать команде разработчиков Гослинга, он предложил бы дать Signed "ноль на бесконечности", чтобы все запросы смещения адресов сначала добавляли свой АЛГЕБРАИЧЕСКИЙ РАЗМЕР КОЛЬЦА, чтобы избежать отрицательных значений.
Таким образом, любое смещение, брошенное в массив, никогда не может генерировать SEGFAULT. Например, в инкапсулированном классе, который я называю RingArray типа double, для которого необходимо поведение без знака - в контексте «самовращающегося цикла»:
Приведенный выше RingArray никогда не получит отрицательный индекс, даже если вредоносный запросчик попытается это сделать. Помните, что существует также много законных запросов для запроса предыдущих (отрицательных) значений индекса.
Примечание: внешний модуль% отменяет ссылки на законные запросы, тогда как внутренний модуль% маскирует явную злобу от негативов, более негативных, чем -модуль. Если бы это когда-либо появилось в Java + .. + 9 || 8 + .. + spec, тогда проблема действительно превратилась бы в «программиста, который не может« самостоятельно вращать »FAULT».
Я уверен, что так называемый «дефицит» в Java unsigned int можно восполнить с помощью одной строки.
PS: Просто для того, чтобы дать контекст вышеприведенному ведению хозяйства RingArray, вот операция-кандидат 'set', соответствующая вышеописанной операции элемента 'get':
источник
Я могу вспомнить один неприятный побочный эффект. Во встроенных базах данных Java число идентификаторов, которые вы можете иметь с полем 32-битного идентификатора, равно 2 ^ 31, а не 2 ^ 32 (~ 2 миллиарда, а не ~ 4 миллиарда).
источник
ИМХО причина в том, что они слишком ленивы, чтобы реализовать / исправить эту ошибку. Предполагать, что программисты на C / C ++ не понимают unsigned, структуру, объединение, битовый флаг ... Это просто нелепо.
Эфир, вы разговаривали с программистом / bash / java, находящимся на грани начала программирования на языке C, без каких-либо реальных знаний об этом языке, или вы просто разговариваете в своем уме. ;)
когда вы каждый день работаете с форматом, будь то файл или оборудование, вы начинаете сомневаться, что, черт возьми, они думают.
Хорошим примером здесь будет попытка использовать неподписанный байт в качестве вращающегося цикла. Для тех из вас, кто не понимает последнее предложение, как на самом деле вы называете себя программистом.
ОКРУГ КОЛУМБИЯ
источник