Re[6]: Нужен ли unsigned
От: remark Россия http://www.1024cores.net/
Дата: 14.11.06 11:08
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, remark, Вы писали:


К>Практически согласен со всем, кроме вот этого


R>>Обратных же примеров, когда замена unsigned на signed ломает код, нет!

R>>Если не считать, что у unsigned чуть больше диапазон. Но стоит ли оно того? Если уж надо хранить действительно большие числа, то имхо лучше воспользоваться int64_t. Тут и диапазон действительно больше, чем у int и проблем не будет.

К>Как только мы начинаем упражняться в работе с битами, проблемы сразу же появляются.

К>- приведение типов (всем хорошо известно, как переводить char в int: (int)(unsigned char)ch)
К>- сдвиг (SHR для беззнаковых и SAR для знаковых)
К>- битовые поля
К>
К>struct bitz
К>{
К>    unsigned u : 1; // принимает значения 0 и 1
К>    int      i : 1; // принимает значения... сюрприз! 0 и -1, потому что старший (единственный) бит - знаковый
К>};
К>



Согласен. Я немного погорячился с таким всеобъемлющим заявлением.
Тогда заявление надо ограничить до "обычных чисел" без битов, флагов и т.д.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: Не! проще таки лучше!
От: Roman Odaisky Украина  
Дата: 14.11.06 11:09
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Ну а с тем, что "эти абстракции" зарыты намного глубже я тоже совершенно согласен.

E>про то и вопрос. От чего в языке фортран или там паскаль массивы было удобно итерировать знаковым индексом, а в C++ + STL стало так трудно и опасно?

Желающие могут попробовать:
var a: array[-1..1] of whatever;
. . .
a[-2] = 0;

много счастья будет?

E>Да, от чего вообще в этом обсуждении возник STL.

E>Собственно ты сам начал проводить аналогии между unsigned индексом и STL-ными итераторами.
E>Действительно и там и там нельзя сделать "лишний шаг"
E>А в знаковом индексе -- можно.

Здесь очень как-то однобоко можно.
int i = . . .;
if(i >= 0)
{
    a[i] = 123; // ладно, так можно...
}

T* p = . . .;
if(p >= first) // Всем искренне желаю, чтоб это всегда выполнялось.
{              // Ибо иначе UB. Причем есть вполне реальная угроза аппаратного исключения
    *p = 123;  // при загрузке в регистр сомнительного указателя (вдруг массив попал в самое начало странички).
}              // Или ОС обругает за выход за границу дозволенной памяти (хотя это тоже маловероятно).


E>После этого ты стал утверждать, что раз уж в STL-way (через указатели и итераторы) итерации лишний шаг делать нельзя, то не надо приучаться к такой возможности при итерации через индекс.


Так это и C++ way, в том-то и дело. Добрый дед Ю. Би с топором.

E>А я во делаю совершенно противоположенный вывод. Раз уж в STL-way делать "лишний шаг" опасно, а часто хочется, то это косяк STL-way.


И опять же. (new X[N]) – 1 — UB. Это вопрос уже к языку. И я бы посмотрел на «правильную» семантику --someDeque.begin(). Или ты считаешь итераторы ошибкой? Может быть. Только что тогда вместо них? Enumerators вряд ли решают эту проблему.

E>Мне кажется, что лучше избегать STL-way итерации.


тот же вопрос... как тогда?

E>Забавно, кстати, что сами авторы STL пожоже это тоже чувствовали. Потому что понаписали всяких for_each


Может, и чувствовали... но вроде есть и более другие поводы для существования for_each.

E>В принципе я их понимаю. Так как простой for() при использовании итераторов и unsigned индексов действительно становится неудобным и опасным


А вот с этим согласен. Бывает. Иногда хочется примерно так:
for(int i = 0; i < n; i += k)
{
    . . . a[i] . . .
}

с итераторами это хоть и можно, но сложнее, придется какой-то свой skip_iterator соображать.
До последнего не верил в пирамиду Лебедева.
Re[12]: Таки проще! :)
От: Erop Россия  
Дата: 14.11.06 11:59
Оценка: 3 (1) +1 -2
Здравствуйте, Roman Odaisky, Вы писали:

RO>Желающие могут попробовать:

RO>
RO>var a: array[-1..1] of whatever;
RO>. . .
RO>a[-2] = 0;
RO>

RO>много счастья будет?
<... много пропустил ...>

RO>с итераторами это хоть и можно, но сложнее, придется какой-то свой skip_iterator соображать.


Собственно мы примерно до одного договрились.
Отличия:

1) В примере с паскалем индекс можно выводить из диапазона [-1..1]. Нельзя по неверному индексу лазить в массив. но это нельзя при любом раскладе что знаковый индекс, что беззнаковый

2) Про доступ к элементу массива с индексом -1 в С++. Та же ровно песня. А итерация массива при помощи указателя -- ИМХО нечитабельно и ненадёжно. И не только потому, что можно за границу сегмента вылететь (на практике это таки трудно часто, так как перед массивами обычно ещё что-нибудь служебное кладут). Короче неудобно это. Люди так не думают. Лучше пусть все занимаются своим делом.
Люди пишут доступ к массивам через индексы, оптимизаторы, если хотят и могут, компилируют это в код, работающий с указателями, а программист оставляет голые указатели для хаккеров и страшных снов

3) Как быть без итераторов?
Собственно я вот отказался от использования STL и его представления об итераторах и не жалею нисколько. И как-то пока ни разу не хотелось вернуться
Я даже не против идеи итератора как такового. Только итераторы надо рожать там, где они действительно нужны, а не всюду и всегда ?)
Просто мне кажется, что для доступа к массиву намного удобнее индекс
А вообще итератор чего-то, как идея, не всегда плох. Хотя то, что ты назвал енумератором, обычно проще в реализации и не сложнее в использовании
Мне особенно не нравятся итераторы из STL потому что они копируют зачем-то семантику указателей.
Вроде как все попробовали и осознали, что писать на голых указателях стрёмно. и не только потому, что не безопасно, но и потому, что непонятно
На кой нарожали три мешка шаблонов, чтобы доступ к довольно высокоуровневым коллекциям, загнуть в такую же уродскую парадигму -- я лисно понять совершенно не могу
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Где тут ошибка
От: Шахтер Интернет  
Дата: 14.11.06 14:33
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Шахтер, Вы писали:


Ш>>
Ш>>void func(char *p,size_t s)
Ш>> {
Ш>>  for(int i=0; i<s ;i++) p[i]=0;
Ш>> }
Ш>>


Ш>>Надо обьяснять, где здесь ошибка?


E>Зачем объяснять?


Действительно незачем. Ответ очевидный.

E>Ошибка в том, что s имеет беззнаковый тип.


Неверно. Очевидно, ответ очевиден не для всех.

E>Она же допущена и в std::vector


См. выше.

E>Ну и что?


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

E>1) реально size таким большим не бывает, так как в память плохо помещается


Неверно. На Win32 -- если система загружена с опцией 3GB. На Win64 вообще int 32 разрядный а size_t 64.

E>2) Лично я и std::vector не пользуюсь. Пользуюсь массивами из другой библиотеки, там размер массива int


Да ради бога.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: Всё очень просто....
От: Шахтер Интернет  
Дата: 14.11.06 14:46
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Шахтер, Вы писали:


E>>>signed -- для чисел

E>>>unsigned -- для флажков.
Ш>>По-моему, это та простота, которая хуже воровства.

E>Ну прости, я ответил на вопрос, что же я таки думаю.

E>ИМХО выгоды от использования беззанковых чисел всегда какие-то призрачные.

Речь идет не а выгодах. Речь идет о том, зачем вообще нужна беззнаковая арифметика (см. заглавную тему).
Она нужна для решения огромного количества задач.

Например, напиши struct IPHeader без беззнаковых типов. Или сделай алгоритм вычисления CRC (а так же SHA, DES, длинная арифметика и.т.п.).

E>Конечно есть какие-то специальные очень случаи, когда хочется именно беззнакового и именно 32-ного числа.


E>Но, это очень большая редкость. Я вот припоминаю только один случай.


Не надо обобщать свой опыт на всю индустрию.

E>Обычно беззнаковые числа хочется использовать для каких-то объектов, которые числами не являютчся (скажем над ними не производят арифметических действий, например).

E>Это или какие-то ID или сборки флагов или ещё какие-нибудь хитрые конструкции. но никак не результат сложения/вычитания/деления/умножения/взятия остатка.

E>пример о котором я помню -- млпдшее слово в руками сделанном двухсловном числе.


E>Кроме того беззнаковость числа ничего хорошего ни в CT ни в RT не гарантирует.


Это утверждение мне непонятно. А что гарантирует знаковость числа?

E>Ну а выгоды я хотел бы узнать (кроме, конечно, выгоды в один бит)


E>Часто выгода в один бит всё равно бесполезна. Ну и потом обычно это всё непереносимо


Что именно непереносимо? И почему? Или слово непереносимо используется в другом значении?
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[6]: Где тут ошибка
От: Андрей Тарасевич Беларусь  
Дата: 14.11.06 14:55
Оценка: +1 :)
Здравствуйте, Erop, Вы писали:

E>Скажем для итерации слоёв в вычислительной схеме. Таки из номера слоя что-нибудь вычитать иногда хочется


Необходимость "что-то вычитать" никак не служит аргументом в пользу знакового типа. Из беззнакового типа тоже можно "что-то вычитать". Если в предметной области допустимы только положительные значения, то получиение отрицательного значения в знаковом типе ничем принципиально не отличается от получения черезменрно большого значения в беззнаковом. Разница только в том, что, как тут уже говорилось, со знаковым типом придется ловить обе ситуации (выход за пределы вниз и вверх), а с беззнаковым только одну. Это, как раз таки, аргумент в пользу беззнакового типа.
Best regards,
Андрей Тарасевич
Re[8]: Нужен ли unsigned
От: Андрей Тарасевич Беларусь  
Дата: 14.11.06 14:59
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>Неверно. 'atoi' и иже с ними — функции "мертвые" и практической ценности не представляющие.

E>А почему?

Потому что не предоставляют никаких осмысленных средств для отлавливания "нечисловых" входных строк и, более существенно, порождают неопределенное поведение в случае переполнения.

'sscanf' позволяет отлавливать "кривые" входы, но опять же порождает неопределенное поведение при переполнении.
Best regards,
Андрей Тарасевич
Re[7]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 14.11.06 14:59
Оценка: :)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Шахтер, Вы писали:


К>>>В знаковой арифметике одно и то же неравенство можно выразить несколькими способами: x<y, x-y<0, 0<y-x, а в


Ш>>В знаковой арифметике эти выражения точно так же не эквивалетны. Кроме того, x<0 не эквивалетно -x>0.


К>Ну не "точно так же".


Именно точно так же. Знаковые x и y или беззнаковые x-y<0 НЕ эквивалентно x<y.

К>Конечно, в области больших чисел есть риск поймать переполнение.

К>Но предусловие "оба числа по абсолютному значению не превосходят MAXINT/2" достаточно распространено, и этим можно пользоваться.

Я честно не понимаю, если нужно узнать, что больше x или y, то зачем писать

x-y<0 вместо x<y ? Зачем искуственно сужать область правильной работы функции?

К>Кстати говоря. Это и плюс, и минус одновременно. С одной стороны, упрощаются выражения, а с другой — есть риск забыть проверки и получить феерверк на больших значениях. Беззнаковая же арифметика не прощает халатности с самого начала.


Я бы всё-таки хотел более конкретных примеров, как упрощаются выражения.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 14.11.06 15:28
Оценка: 2 (1) :)
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>Беззнаковые по своей природе сущности естественно представлять беззнаковыми типами. Тут, собственно, и вопросов никаких нет.


R>Я всеми руками за типизацию.


Типизация здесь не причем. Вообще.

R>Если у переменной только два значения, то надо использовать bool, а не int. Если значение не меняется, то надо использовать const. Это замечательно, когда компилятор отлавливает ошибки. Это надо использовать всегда. Всегда, за исключением одного случая. Не надо использовать unsigned. Почему? Из-за реализации в языке. Проблема в том, что компилятор не отловит ошибки. Ну не отловит он и всё. И это получается ещё хуже, т.к. появляется чувство ложной уверенности. Думаешь, я завёл unsigned — всё, все мои проблемы решены. А на самом деле ничего не решено и компилятор практически ничего не контролирует.


R>Я могу, конечно, поприводить примеры типа таких:


R>
R>    unsigned u = 0;
R>    int i = 0;
R>    u = i;
R>    i = u;
R>    // msvc80sp1 уровень предупреждений 4 — ни одного варнинга. Хотя оба из присваиваний могут вызвать проблемы...
R>


R>
R>    std::vector<int> v (3);
R>    for (size_t i = v.size() - 1; i >= 0; --i)
R>        std::cout << v[i];
R>


R>Или вот ещё статья недавно проскакивала.


R>Но достаточно просто оценить какой шум вокруг этой темы вот уже на протяжении десятилетий. Десятилетиями программисты наступают на одни и те же грабли. Причём не самые плохие программисты (и вы предлагаете понаступать на них ещё немного всем нам). Почему? Они тоже надеются, что компилятор им чем-то поможет. Они тоже думают, что они повышают типизацию.


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

R>Фразы типа:

R>

R>я считаю, что правильнее внимательнее относиться к коду, а не пытаться компенсировать лень использованием знаковых типов

R>Это из идеального мира. Действительно, давайте просто внимательно писать программы без ошибок.
R>В реальном мире, к сожалению, не так. Программисты работают по вечерам, по 12 часов, в спешке и т.д. Все мы писали и одинарное равно в if'е вместо двойного, и код типа примера выше и т.д.

R>И очень бы хотелось, что бы при написании программ не надо было проявлять чудеса внимательности и памяти.


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

R>

R>знаковые типы просто-напросто чаще "прощают" беспечное отношение к коду


R>Знаковые типы не просто прощают беспечное отношение к коду, они действительно заставляют больше кода работать корректно. Почувствуйте разницу. Посмотрите на цикл вверху. Что бы заставить его работать достаточно просто заменить size_t на int. Всё. Код будет корректным и рабочим.


Нет, не будет. v.size()-1 не обязательно представимо положительным int. Фокус не удался.

    std::vector<int> v (3);
    for (size_t i = v.size() - 1; i!=size_t(-1) ; --i)
        std::cout << v[i];


Можно сделать вот так.

    std::vector<int> v (3);
    for (size_t i = v.size() ; i-- ;)
        std::cout << v[i];


Но лучше вот так.

R>Посмотрите пример в статья. Всё что достаточно сделать, что бы там код заработал. Правильно. Заменить unsigned на int.


R>Работу этого кода сломало единственное — замена signed на unsigned. Причём тоже из благих намерений. В цикле мы по каким индексам хотим пробежать? От size()-1 до 0. Может быть отрицательным? Нет. Заменяем signed на unsigned — код перестаёт работать!


R>В примере в статье процент в каком диапазоне может быть? От 0 до 100. Может быть отрицательным? Нет. Заменяем signed на unsigned — код (опять) перестаёт работать!


R>Я думаю таких примеров можно найти ещё.


Примеров откровенного ламерства, когда люди простейший цикл не могут написать, действительно можно найти вагон и прицепную тележку.

R>Обратных же примеров, когда замена unsigned на signed ломает код, нет!


Постановка вопроса некорректна. Это примерно тоже самое, что экспериментирвать, что будет если в топливный бак вместо саляры залить бензин или наоборот.
Сломается японская пила или нет?

R>Если не считать, что у unsigned чуть больше диапазон. Но стоит ли оно того? Если уж надо хранить действительно большие числа, то имхо лучше воспользоваться int64_t. Тут и диапазон действительно больше, чем у int и проблем не будет.


Проблемы тут будут те же самые. Ну нет в компьютере натуральных чисел и не будет.
Точно так же нет вещественных, и всё что мы имеем -- это жалкий float.

R>Я недавно думал над этим вопросом. И изначально тоже отталкивался от точки, что всё должно быть максимально типизировано. И что надо использовать unsigned. Но потом после анализа таких примеров и кучи блогов, статей, постов по поводу ошибок связанных с unsigned, пришёл к указанному выводу — типизация везде, кроме unsigned. Ну не работает оно так как хочется. Не работает.


R>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[6]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 14.11.06 15:29
Оценка:
Здравствуйте, Nuzhny, Вы писали:

N>Добавлю ещё чуть-чуть: нет функций преобразования С-строк к unsigned типам. Есть atoi, atol, atoi64. И ни одного unsigned.


Ты наверно хотел сказать -- нет в CRT. Ну и что?
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[8]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 14.11.06 15:31
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>Неверно. 'atoi' и иже с ними — функции "мертвые" и практической ценности не представляющие.

E>А почему?

Например, потому что не дают никакой диагностики.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[6]: Нужен ли unsigned
От: remark Россия http://www.1024cores.net/
Дата: 14.11.06 15:46
Оценка: +1 -1 :)
Здравствуйте, Шахтер, Вы писали:

Ш>Здравствуйте, remark, Вы писали:


R>>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>>Беззнаковые по своей природе сущности естественно представлять беззнаковыми типами. Тут, собственно, и вопросов никаких нет.


R>>Я всеми руками за типизацию.


Ш>Типизация здесь не причем. Вообще.


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



Ш>Этот шум не стоит выеденного яйца. Беззнаковые типы широко используются в программировании и будут использоваться, поскольку без них многие задачи вообще не решаются. Так что нужно не шуметь, а просто выучить беззнаковую арифметику и научится грамотно её использовать -- там где она необходима.

Ш>Ну и кстати, понимание того, где какую арифметику нужно использовать тоже приходит со знаниями и опытом.

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


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


Да. Только для одного кода их почему-то надо значительно больше чем для другого.
В одном коде почему-то приходится напрягаться до максимума, что бы уследить и удержать в памяти все тонкие моменты (и не дай бог к тебе кто-нибудь подойдёт с глупым вопросом в этот момент), а в другом коде как-то без особых напрягов получается разбираться и модифицировать.


R>>

R>>знаковые типы просто-напросто чаще "прощают" беспечное отношение к коду


R>>Знаковые типы не просто прощают беспечное отношение к коду, они действительно заставляют больше кода работать корректно. Почувствуйте разницу. Посмотрите на цикл вверху. Что бы заставить его работать достаточно просто заменить size_t на int. Всё. Код будет корректным и рабочим.


Ш>Нет, не будет. v.size()-1 не обязательно представимо положительным int. Фокус не удался.


Если уж на то пошло, то ты уверен, что для любого контейнера размер представим и unsigned? Фокус тоже не удался. Ну заменили int на unsigned и что? Ну в два раза увеличился диапазон.
Ну если уж вернуться на землю, то я думаю, что не сильно ошибусь, если скажу, что для 99% всех используемых контейнеров int'a хватит.


Ш>
Ш>    std::vector<int> v (3);
Ш>    for (size_t i = v.size() - 1; i!=size_t(-1) ; --i)
Ш>        std::cout << v[i];
Ш>


Ш>Можно сделать вот так.


Ш>
Ш>    std::vector<int> v (3);
Ш>    for (size_t i = v.size() ; i-- ;)
Ш>        std::cout << v[i];
Ш>


Ш>Но лучше вот так.


Ну тут можно до бесконечности соревноваться в мастерстве... а можно просто написать код и он будет работать.


Ш>Примеров откровенного ламерства, когда люди простейший цикл не могут написать, действительно можно найти вагон и прицепную тележку.


Да, да. Уволим уже наконец всех этих ламеров!


R>>Обратных же примеров, когда замена unsigned на signed ломает код, нет!


Ш>Постановка вопроса некорректна. Это примерно тоже самое, что экспериментирвать, что будет если в топливный бак вместо саляры залить бензин или наоборот.

Ш>Сломается японская пила или нет?

Почему?


R>>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Решите тогда задачу
От: Андрей Тарасевич Беларусь  
Дата: 14.11.06 15:48
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>И все таки интересно, какую связь этой задачи с данной дискуссией видит автор?


RO>А ты попробуй ее реши


Я ее уже давно решил. Мое решение выглядит так

unsigned f(unsigned n, int s)
{
  return s >= 0 ? s % n : n - (-s - 1) % n - 1;
}


RO>Хинт:

RO>
RO>-1 % 10 = -1
RO>-1 % 10u = 5
RO>
(хотя хотелось бы видеть 9)


Да, но непоcредственно для решения данной задачи и в первом случае хотелось бы видеть '9', а не '-1'. Проблема тут не в знаковости/беззнаковости, а в рекомендуемом в С/С++ (требуемом в С99) поведении операторов деления и взятия остатков, о которых ты сам же пишешь ниже. Знаковый тип тоже не дает желаемого результата. Поэтому я снова спрашиваю: какое это все имеет отношение к обсуждаемому вопросу?

(Да, о поведении выражений со смешанными знаковыми/беззнаковыми операндами надо помнить. Но в этом-то примере основная проблема именно в делении.)

RO>Как эту задачу решить правильно, я затрудняюсь сказать. В псевдокоде она решается одной строчкой:

RO>
RO>unsigned f(unsigned n, int s)
RO>{
RO>    return s % n;
RO>}
RO>
но правила C/C++ чуть изменяют поведение оператора % (по сравнению с математической его версией), в результате чего всё становится с ног на голову.


Совершенно верно, но переход к знаковым типам ничего в данном случае не решает.
Best regards,
Андрей Тарасевич
Re[5]: Решите тогда задачу
От: Шахтер Интернет  
Дата: 14.11.06 15:57
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>И все таки интересно, какую связь этой задачи с данной дискуссией видит автор?


RO>А ты попробуй ее реши


Можно мне?

unsigned mod(unsigned n,int s)
 {
  if( s>=0 ) return unsigned(s)%n;
  
  return n-1-(-unsigned(s)-1)%n;
 }


RO>Как эту задачу решить правильно, я затрудняюсь сказать. В псевдокоде она решается одной строчкой:

RO>
RO>unsigned f(unsigned n, int s)
RO>{
RO>    return s % n;
RO>}
RO>
но правила C/C++ чуть изменяют поведение оператора % (по сравнению с математической его версией), в результате чего всё становится с ног на голову.


C/C++ тут не причем. Причем здесь -- аппаратура. Поведение деления при отрицательных операндах может быть разным на разных машинах.
Это прблема не языка, а нестандартизованности знаковой арифметики.

Собственно говоря, ты привел хороший пример задачи, не решаемой без привлечения беззнаковых чисел.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 14.11.06 16:01
Оценка: +1
Здравствуйте, last_hardcoder, Вы писали:

_>Здравствуйте, Аноним,


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


Я совершенно согласен, что в оконном менеджменте нет большого смысла использовать беззнаковые числа. Вопрос об использовании знаковой или беззнаковой арифметики должен решаться исходя из существа задачи.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[7]: Где тут ошибка
От: Erop Россия  
Дата: 14.11.06 16:34
Оценка: 1 (1) +1 -1 :)
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Необходимость "что-то вычитать" никак не служит аргументом в пользу знакового типа. Из беззнакового типа тоже можно "что-то вычитать". Если в предметной области допустимы только положительные значения, то получиение отрицательного значения в знаковом типе ничем принципиально не отличается от получения черезменрно большого значения в беззнаковом. Разница только в том, что, как тут уже говорилось, со знаковым типом придется ловить обе ситуации (выход за пределы вниз и вверх), а с беззнаковым только одну. Это, как раз таки, аргумент в пользу беззнакового типа.



Нет уж. Числа лучше бы использовать нормальные.
И отлаживать проще и программировать и всё такое.

Это примерно так же, как если величина принимает толкьо чётные значения, то надо хранить от неё половину
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: А почему так "немножечко нервно"? :)
От: Erop Россия  
Дата: 14.11.06 16:41
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>А то что без беззнаковых типов невозможно писать надежный и переносимый код в этом и во многих других случаях.

Ну это просто враньё
Есть просто вагоны софта с знаковыми числавми и переносимого и вообще по всякому хорошего.

Кроме всего прочего, если мы таки всё ещё обсуждаем итерацию массива в обратном порядке, то я хотел бы узнать про источники ненадёжности или непеиеносимости такого вот кода:

int size = ***;
my_array<***> array( size );
for( int i = size - 1; i >= 0; i-- )
    array[i] = 0;




E>>1) реально size таким большим не бывает, так как в память плохо помещается
Ш>Неверно. На Win32 -- если система загружена с опцией 3GB. На Win64 вообще int 32 разрядный а size_t 64.

Ну-ну. Давай, попробуй, а потом расскажешь про двухгигабайтные массивы под 3Gb.


Ну а что касается, довольно таки пока что мифической истории про террабайтные массивы под Win64, то даже и там проблема будет не с тем, что индекс знаковый, а с тем, что индекс 32-разрядный

В дырку на стыке знаковости/беззнаковости на 64-битных индексах попасть ещё сложнее, чем на 32-разрядных


E>>2) Лично я и std::vector не пользуюсь. Пользуюсь массивами из другой библиотеки, там размер массива int
Ш>Да ради бога.
Нервный ты какой-то.
Нет бы вот чтобы спокойно обсудить что и как
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Нужен ли unsigned
От: Кодт Россия  
Дата: 14.11.06 16:44
Оценка: +2
Здравствуйте, Шахтер, Вы писали:

Ш>Я честно не понимаю, если нужно узнать, что больше x или y, то зачем писать

Ш>x-y<0 вместо x<y ? Зачем искуственно сужать область правильной работы функции?

К>>Кстати говоря. Это и плюс, и минус одновременно. С одной стороны, упрощаются выражения, а с другой — есть риск забыть проверки и получить феерверк на больших значениях. Беззнаковая же арифметика не прощает халатности с самого начала.


Ш>Я бы всё-таки хотел более конкретных примеров, как упрощаются выражения.


Пожалуйста. Пусть даны 4 числа, задающие отрезки [a;b] и [c;d]. Нужно выяснить, какое значение — b-a или d-c — больше. При том, что в предусловии не сказано, что a<=b и c<=d.

Естественное предусловие — |a|,...,|d| < MAXINT/2.
bool ab_less_than_cd = b-a < d-c; // интуитивно понятное (справедливо только для signed)

bool ab_less_than_cd = b+c < a+d; // для случая unsigned, избавились от вычитания... что за величины такие странные: b+c? a+d?

bool ab_less_than_cd = (int)(b-a) < (int)(d-c); // мы утверждаем, что разность - знаковая величина.
// Окей, как насчёт unsigned short или unsigned long? Нужно ввести некий signed_cast, приводящий к знаковому типу подходящего размера

bool ab_less_than_cd = a<b && (d<=c || b-a<d-c) || b<=a && (c<d || c-d<=a-b); // код, свободный от граничных условий... ничерта не понятный и возможно, с ошибками
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: Всё очень просто....
От: Erop Россия  
Дата: 14.11.06 16:50
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Речь идет не а выгодах. Речь идет о том, зачем вообще нужна беззнаковая арифметика (см. заглавную тему).

Ш>Она нужна для решения огромного количества задач.

1) Вообще беззнаковая арифметика нужна в C++ в основном для того, чтобы работать со всякими странными объектами, которые на самом деле числами не являются, но от чего-то в C и С++ числами предстваленны. Вот в паскале нету никакой беззнаковой арифметики и ничего.
Да и в математике тоже нету

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

Ш>Например, напиши struct IPHeader без беззнаковых типов. Или сделай алгоритм вычисления CRC (а так же SHA, DES, длинная арифметика и.т.п.).


Вот конкретно длинная арифметика -- единственный пример, который я посмню, где именно беззнаковая арифметика была в тему.
А CRC нет никакой проблемы считать и так и сяк и по всяк.

E>>Конечно есть какие-то специальные очень случаи, когда хочется именно беззнакового и именно 32-ного числа.

E>>Но, это очень большая редкость. Я вот припоминаю только один случай.
Ш>Не надо обобщать свой опыт на всю индустрию.
Ну ты тоже вроде только его и привёл

E>>Обычно беззнаковые числа хочется использовать для каких-то объектов, которые числами не являютчся (скажем над ними не производят арифметических действий, например).

E>>Это или какие-то ID или сборки флагов или ещё какие-нибудь хитрые конструкции. но никак не результат сложения/вычитания/деления/умножения/взятия остатка.

E>>Кроме того беззнаковость числа ничего хорошего ни в CT ни в RT не гарантирует.

Ш>Это утверждение мне непонятно. А что гарантирует знаковость числа?
Тоже ничего не гарантирует, кроме того, что труднее попасть в переполнение по вычитанию
Но в целом в математике и вообще в мозгу нормального среднего человека числа вполне себе знаковые. И в предметной области тоже занковые.
Даже если какая-то конкретная числовая величина беззнаковая, то разность двух таких величин всё равно будет знаковой.
Короче знаковая арифметика -- общий случай высокого уровня. Беззнаковая -- хитрый полухаккерский трюк, который удобно устроить на почти всех компьютерах. Но для того, чтобы такой трюк использовать, надо бы чтобы он был чем-то лучше простого и понятного общего случая


E>>Ну а выгоды я хотел бы узнать (кроме, конечно, выгоды в один бит)

E>>Часто выгода в один бит всё равно бесполезна. Ну и потом обычно это всё непереносимо
Ш>Что именно непереносимо? И почему? Или слово непереносимо используется в другом значении?

Ну та ситуация, что 31 бита не хватает, а 32 хватает.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Где тут ошибка
От: Андрей Тарасевич Беларусь  
Дата: 14.11.06 17:46
Оценка: -1 :)
Здравствуйте, Erop, Вы писали:

АТ>>Необходимость "что-то вычитать" никак не служит аргументом в пользу знакового типа. Из беззнакового типа тоже можно "что-то вычитать". Если в предметной области допустимы только положительные значения, то получиение отрицательного значения в знаковом типе ничем принципиально не отличается от получения черезменрно большого значения в беззнаковом. Разница только в том, что, как тут уже говорилось, со знаковым типом придется ловить обе ситуации (выход за пределы вниз и вверх), а с беззнаковым только одну. Это, как раз таки, аргумент в пользу беззнакового типа.


E>Нет уж. Числа лучше бы использовать нормальные.

E>И отлаживать проще и программировать и всё такое.

Не вижу в этом сообщении содержания. Соответственноо и ответить ничего содержательного не могу.
Best regards,
Андрей Тарасевич
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.