[java] Кодирование данных

yroslavasako

На сях удобно писать кодеры с использованием unsigned int, сдвигов, целочисленного деления с остатком. Как это всё пишется на java? Там нету unsigned данных, для signed - проблемы с неправильным дивом, который для x > 0 делает floor, для x < 0 - ceiling. Может у кого есть пример быстрого (не побитового) арифметического кодера под яву?

kill-still

поясни, что ты понимаешь под кодером?

yroslavasako

поясни, что ты понимаешь под кодером?
что-нибудь, что вручную обрабатывает поток данных и кодирует их в другой поток. Смысл - чтобы всё было компактно и занимало меньше место. Например, кодирование с помощью арифметического сжатия.

Maurog

что-нибудь
в гугле забанили? почему думаешь, что посетители форума тебе быстрее помогут, нежели гугл?

katrin2201

Там с unsigned операциями действительно гемор.
Самый простой способ - это пихать свое число в бОльший тип (например если хочешь unsigned int - бери long и как все сделал, отрезать по маске и кастить обратно в инт.

yroslavasako

в гугле забанили? почему думаешь, что посетители форума тебе быстрее помогут, нежели гугл?
гугл больше показывает флеймов на тему "вы не должны хотеть unsigned int" чем ответов
плюс здесь гарантировано есть студенты (бывшие) ватолинского спецкурса, вдруг кто из них пробовал яву

yroslavasako

Самый простой способ - это пихать свое число в бОльший тип (например если хочешь unsigned int - бери long и как все сделал, отрезать по маске и кастить обратно в инт.
сказывается инерция мышления. Мне это даже в голову не пришло :(

kill-still

в jdk вообще все эти твои т.н. кодеры на нативе написаны.
например sun.nio.cs.MS1251$Encoder

yroslavasako

в jdk вообще все эти твои т.н. кодеры на нативе написаны.
ну я так и думал. скорость важна, а других инструментов в яве нет, кроме натива. Я так полагаю, что разработчики явы инт считали исключительно чем-то вроде хранителя счётчика или единиц товара на складе. Int как данные не рассматривался при составлении ТЗ.

schipuchka1

не, ну можно посмотреть на исходники, скажем, оракловых драйверов
http://code.google.com/p/ora-jdbc-source/source/browse/trunk...

bleyman

Я думаю они опасались (и продолжают опасаться) что кодеры начнут воротить педерастию как Дийкстра (кажется) заповедовал и Степанов например был замечен в — использовать uints для счётчиков циклов и вообще для переменных/параметров которые "логически" не могут быть отрицательными.
Почему это педерастия: потому что uint32 это математический объект "элемент кольца вычетов по модулю 2^32", а вовсе не "неотрицательное число". В своей истинной роли он удобен для всякой побитовой арифметики, да, а вот к использованию в роли "неотрицательного числа" он категорически непригоден ибо не кидает эксепшена при underflow (что противоречило бы наоборот истинной роли а даже если б и кидал то этого было бы недостаточно для вменяемого использования в цикле от 10 до 0, например.
http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...

Dasar

можно было их во framework добавить, но не делать кратких имен в языке, а оставить имена вида: bla.bla.SpecialUnsignedInt32

Maurog

Почему это педерастия: потому что uint32 это математический объект "элемент кольца вычетов по модулю 2^32", а вовсе не "неотрицательное число"
есть какие-то более развернутые аргументы на этот счет? я в C++ коде использую uint именно для неотрицательных чисел и не считаю это неправильным

kill-still

по-моему тоже ничего криминального.

evolet

есть какие-то более развернутые аргументы на этот счет? я в C++ коде использую uint именно для неотрицательных чисел и не считаю это неправильным
пример:
ну вот есть у тебя условие (a < b + c) и пусть по смыслу все числа неотрицательные (длины там или количества) и вот ты для наглядности переписываешь это условие эквивалентным образом (a - b < c).
И тут сюрприз! если переменные uint'ы - то это преобразование будет уже не эквивалентным (при например a=0 b=1 c=0).

Dasar

есть какие-то более развернутые аргументы на этот счет? я в C++ коде использую uint именно для неотрицательных чисел и не считаю это неправильным
при использовании uint уменьшается запас прочности кода и иногда нарушается принцип наименьшего удивления ( http://en.wikipedia.org/wiki/Principle_of_least_astonishment )
например, следующий код никогда не завершается при a = 0, хотя это и не очевидно при беглом взгляде

uint a = GetMinBorder;

for (uint i = 10; i >= a; --i)
{
..
}

yroslavasako

например, следующий код никогда не завершается при a = 0, хотя это и не очевидно при беглом взгляде
при a = 0 выполняется инвариант unsigned int: x >= 0. Так что никакого удивления нет, зря ты его сюда приплёл. Проблема не в том, что unsigned не очевиден, а в том что особо одарённые программисты не могут одновременно запомнить что такое signed и unsigned типы и забывают какая переменная какому типу принадлежит.

Dasar

при a = 0 выполняется инвариант unsigned int: x >= 0
для переменной цикла этот инвариант не выполняется

yroslavasako

для переменной цикла этот инвариант не выполняется
это как? любой uint >= 0.

Dasar

это как? любой uint >= 0.
uint да, а переменная цикла, которая пробегает по убывающей последовательности uint-ов имеет уже инвариант >= -1, что выходит за uint.

yroslavasako

перменная цикла имеет тип uint и наследует его инвариант. При этом в полном соответствии с типом, как ты метко заметил кольца вычетов по модулю 2^32, 0 - 1 = 2^32-1
Для избежания подобных бед восприятия я бы не отменял бы uint, а сделал бы так, чтобы константы типа uint 12u, 0u, приводились бы к signed int только явно и наоборот, 0 и 12 к uint тоже надо было бы приводить явно

ppplva

Как это поможет? В этом примере константа только одна - 10 в инициализаторе i. Программист, написавший такой цикл, радостно заменит ее на 10u и ничего не изменится.
Проблема unsigned не в кольце, а в том, что, как правило, вычисления делаются возле нижней границы его диапазона, и легко промахнуться. Если считать в знаковых интах рядом с их границей - будет еще хуже, там сразу UB.
Ну и еще такой момент что unsigned при случае промоутится в int, а не наоборот. Поэтому, чтобы использовать верхнюю половину диапазона, нужно аккуратно писать код, и компиляторы обычно предупреждают о смешанных сравнениях.

Dasar

При этом в полном соответствии с типом, как ты метко заметил кольца вычетов по модулю 2^32, 0 - 1 = 2^32-1
это всё отлично, но только опять же никоим образом не совпадает с семантикой переменной цикла. Переменная цикла требует непрерывных целых чисел, без всяких вычетов.

ava3443

Ну и еще такой момент что unsigned при случае промоутится в int, а не наоборот.
только ровно наоборот - signed промоутится в unsigned, и именно поэтому и warning.
unsigned при случае промоутится в long но только на платформах где sizeof(long) > sizeof(unsigned т.е. только в 64-битной режиме на всех юниксах/линуксах. Для 64-бит на винде и для любых 32-бит — см. выше.

Marinavo_0507

ну это просто в C плохой for

yroslavasako

ну это просто в C плохой for
то ли дело в лиспе

Dasar

ну это просто в C плохой for
покажи, пожалуйста, правильный for, для которого не будет данной проблемы.

Marinavo_0507

ну паскалевский

Dasar

ну паскалевский
если задавать через downto, то да.
но for это лишь частный пример глобальной проблемы:
значительное кол-во алгоритмов работающих с числовым диапазоном [a;b] могут внутри себя переходит к диапазону [a - delta; b + delta], что не составляет проблемы, пока диапазон [a;b] с обоих сторон много меньше, чем весь диапазон значений используемого типа данных,
но если работа происходит на границе диапазона, то это требует аудита реализации всех используемых алгоритмов - не расширяют ли они используемый диапазон для внутренней работы или при работе с вырожденными случаями.
При использовании uint-а работа почти всегда происходит на границе поддерживаемого диапазона, что делает обязательным такой аудит. Но на практике такой аудит редко проводится, что и приводит к снижению устойчивости кода к ошибкам.

Marinavo_0507

можно запретить вычитания и декремент для unsigned например

Dasar

можно запретить вычитания и декремент для unsigned например
и зачем тогда такой урезанный uint? всего лишь ради увеличения диапазона в два раза при работе с циклами?

Marinavo_0507

для сдвигов, деления с остатком, битовых операций

Dasar

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

agaaaa

покажи, пожалуйста, правильный for, для которого не будет данной проблемы.
Любой foreach + правильные генераторы. Кстати да, индексные циклы - зло.
uint нужен, чтобы не писать каждый раз проверку на >= 0 для заведомо неотрицательных величин вроде размера или индекса.

Marinavo_0507

uint нужен, чтобы не писать каждый раз проверку на >= 0 для заведомо неотрицательных величин вроде размера или индекса.
фигня же
когда загружаешь эту величину в переменную, надо проверять всё равно

ppplva

Ну да, вместо этого пишешь проверку на <size.

agaaaa

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

Marinavo_0507

если ты пишешь unsigned x = get_some_value ;
то нужно самому проверить, что get_some_value возвращает неотрицательное значение, иначе получится какая-то фигня, и так при любом присваивании

agaaaa

то нужно самому проверить, что get_some_value возвращает неотрицательное значение, иначе получится какая-то фигня, и так при любом присваивании
Если get_some_value уже unsigned - то не нужно.
Если нет, то проверку придётся делать что в случае с signed, что с unsigned. Но в последним случаем в некоторых языках достаточно будет воспользоваться checked преобразованием.

Marinavo_0507

Если get_some_value уже unsigned - то не нужно.
ну оно каким-то образом получилось внутри функции - тогда проверка должна была быть там
то проверку придётся делать что в случае с signed, что с unsigned.
ну я про то и говорю, что никакой особой беззнаковой магии нет: если например вычисляешь разность двух величин, результат может быть отрицательным - такова жизнь

tucha96

особо одарённые программисты не могут одновременно запомнить что такое signed и unsigned типы и забывают какая переменная какому типу принадлежит
вот суки а
что еще забывают?

yroslavasako

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

Dasar

что еще забывают?
имхо, они вообще ничего не помнят. Стандартный ответ: фиг его знает, посмотри в коде.

tucha96

ну вот и я про то же
Оставить комментарий
Имя или ник:
Комментарий: