каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 19:51
Оценка: 158 (14) :)
... где-то форматируется маленький несчастный одинокий винчестер.

winnie надыбал потрясающий пример, как из пня сделать крэй-1.
Я немножко дополировал и заретушировал его.
А теперь внимание, вопрос, где здесь чёрный ящик.
#include <iostream>

int main()
{
    int x = 27;
    for(int i=0; i < 10; ++i)
    {
        std::cout << i << " : " << i*1000000000 << " : " << x << std::endl;
        if(x==1) break;
        x = x%2 ? x*3+1 : x/2;
    }
}
Перекуём баги на фичи!
Re: каждый раз, когда вы пишете i++ + ++i...
От: Sni4ok  
Дата: 18.06.14 19:56
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А теперь внимание, вопрос, где здесь чёрный ящик.

К>
К>        std::cout << i << " : " << i*1000000000 << " : " << x << std::endl;
К>


sizeof(int) на вашей платформе какой?
Re[2]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 20:08
Оценка:
Здравствуйте, Sni4ok, Вы писали:

S>sizeof(int) на вашей платформе какой?


4-байтный.
Перекуём баги на фичи!
Re[3]: каждый раз, когда вы пишете i++ + ++i...
От: watchmaker  
Дата: 18.06.14 20:12
Оценка:
Здравствуйте, Кодт, Вы писали:

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


S>>sizeof(int) на вашей платформе какой?


К>4-байтный.


А байт на вашей платформе какой? :)
Re: каждый раз, когда вы пишете i++ + ++i...
От: watchmaker  
Дата: 18.06.14 20:14
Оценка:
Здравствуйте, Кодт, Вы писали:

К> где здесь чёрный ящик.

  тут
i*1000000000 — переполнение int — UB.

Так, например, в эксперименте с gcc и с INT_MAX == 231-1, компилятор вполне разумно считает, что без переполнения i не может быть больше 2. А раз 2 < 10, то и выход по условию (i < 10) невозможен, так что его и проверять не стоит. Впрочем другие компиляторы по другому чудят.
Re[4]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 20:16
Оценка:
Здравствуйте, watchmaker, Вы писали:

К>>4-байтный.

W>А байт на вашей платформе какой?

Ну если это всё ещё пень, а не крэй, то 8-битный.
Да, там умножение на миллиард, для i=3 происходит целочисленное переполнение.
И?

Подчёркиваю: у меня воспроизвелось в реальных условиях, безо всякого злого колдунства, и хоть диск я успел спасти от форматирования, но эффект наблюдал занимательнейший.
Перекуём баги на фичи!
Re[2]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 20:17
Оценка:
Здравствуйте, watchmaker, Вы писали:

К>> где здесь чёрный ящик.

W>cut=тут

Ты зналъ!
Перекуём баги на фичи!
Re: каждый раз, когда вы пишете i++ + ++i...
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 18.06.14 20:24
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А теперь внимание, вопрос, где здесь чёрный ящик.

  Скрытый текст
К>
К>#include <iostream>

К>int main()
К>{
К>    int x = 27;
К>    for(int i=0; i < 10; ++i)
К>    {
К>        std::cout << i << " : " << i*1000000000 << " : " << x << std::endl;
К>        if(x==1) break;
К>        x = x%2 ? x*3+1 : x/2;
К>    }
К>}
К>


Лопата в переполнении?
Маньяк Робокряк колесит по городу
Re[2]: каждый раз, когда вы пишете i++ + ++i...
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 18.06.14 20:41
Оценка: +1
Здравствуйте, watchmaker, Вы писали:

К>> где здесь чёрный ящик.

W>i*1000000000 — переполнение int — UB.

Непонятно, почему это UB вообще ломает всё, а не только одно вычисленное выражение.
Вот за такие шутки авторов таких компиляторов бить по наглым рыжим мордам.
Ну или требовать -fwrapv в обязательные опции по умолчанию.

UPDATE[2019-06-30]: сейчас так не думаю. Считаю, что обязательно ввести в язык (оба, раз речь про C/C++):
— уровень 1: операции типа {add,sub,mul,bsl}_overflow с выставлением флага по факту переполнения; такое же для конверсии со сжатием размера; это уже даст переносимую возможность эффективно проверять такое вручную;
— уровень 2: шаблонные функции типа checked_add_with_flag, truncating_mul;
— уровень 3: синтаксические контексты для выбора характера операции, задаваемые атрибутами выражения или блока, а до конца блока, функции или входного файла — прагмами.

Обоснование: оптимизации на основании возможности компилятору предполагать, что переполнение не планировалось, таки нужны, но в очень малой доле (грубо говоря, 5%) от всего кода, а для остального (то есть по умолчанию) должны быть максимально сильные меры по отлову и немедленной генерации ошибки (исключения).
The God is real, unless declared integer.
Отредактировано 30.06.2019 6:11 netch80 . Предыдущая версия .
Re[2]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 21:04
Оценка:
Здравствуйте, Marty, Вы писали:

M>Лопата в переполнении?


В переполнении только черенок от лопаты, а вот лезвие — в шапке цикла.
Перекуём баги на фичи!
Re[3]: каждый раз, когда вы пишете i++ + ++i...
От: watchmaker  
Дата: 18.06.14 21:06
Оценка:
Здравствуйте, netch80, Вы писали:

N>Непонятно, почему это UB вообще ломает всё, а не только одно вычисленное выражение.

Так это же суть UB. Или ты не видел тот пример с форматированием диска и clang?

N>Вот за такие шутки авторов gcc бить по наглым рыжим мордам.

Какой-то невероятно нелогичный выбор кого бить
Это же комитет сделал в этом месте UB.
А вот gcc наоборот сделал implementation defined вместо undefined, предоставив тот же -fno-strict-overflow. Ну или упомянутый -fwrapv с ещё более строгим поведением.

N>Ну или требовать -fwrapv в обязательные опции по умолчанию.

Ну это же легко исправляется. Собственно, всё равно же в makefile всё вот это нужно писать.
Уж лучше требуй чтобы -Wall включили, или чтобы -std= со стандартным языком включили по умолчанию (а не с той дикой смесью из нескольких стандартов и расширений, что активна по-умолчанию сейчас) — вот где боль.
Re[3]: каждый раз, когда вы пишете i++ + ++i...
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 18.06.14 21:07
Оценка:
Здравствуйте, Кодт, Вы писали:

M>>Лопата в переполнении?


К>В переполнении только черенок от лопаты, а вот лезвие — в шапке цикла.


Мой cl v14 все нормально переполнил и напечатал

Надо было написать, каким компилятором компилить
Маньяк Робокряк колесит по городу
Re[5]: каждый раз, когда вы пишете i++ + ++i...
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 18.06.14 21:08
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ну если это всё ещё пень, а не крэй, то 8-битный.

К>Да, там умножение на миллиард, для i=3 происходит целочисленное переполнение.
К>И?

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


А что произошло, раскрой интригу?
Маньяк Робокряк колесит по городу
Re[2]: каждый раз, когда вы пишете i++ + ++i...
От: smeeld  
Дата: 18.06.14 21:24
Оценка:
Здравствуйте, watchmaker, Вы писали:

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


К>> где здесь чёрный ящик.

W>
  тут
i*1000000000 — переполнение int — UB.

W>Так, например, в эксперименте с gcc и с INT_MAX == 231-1, компилятор вполне разумно считает, что без переполнения i не может быть больше 2. А раз 2 < 10, то и выход по условию (i < 10) невозможен, так что его и проверять не стоит. Впрочем другие компиляторы по другому чудят.


Что то у меня честно проверял i<10 на каждой итерации.


0 : 0 : 27
1 : 1000000000 : 82
2 : 2000000000 : 41
3 : -1294967296 : 124
4 : -294967296 : 62
5 : 705032704 : 31
6 : 1705032704 : 94
7 : -1589934592 : 47
8 : -589934592 : 142
9 : 410065408 : 71

sizeof(int)==4, arch==x86_64, gcc -4.4.7
Re[3]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 21:25
Оценка:
Здравствуйте, netch80, Вы писали:

N>Непонятно, почему это UB вообще ломает всё, а не только одно вычисленное выражение.


Ну вот смотри, итерации 0, 1, 2 проходят успешно.
На итерации 3 случилась беда. Дальше может быть всё, что угодно.
Компилятору было угодно не форматировать винчестер, а крикнуть IDDQD.

N>Вот за такие шутки авторов gcc бить по наглым рыжим мордам.

N>Ну или требовать -fwrapv в обязательные опции по умолчанию.

Горе от ума какое-то. Такая агрессивная преждевременная оптимизация, точно по заветам Дейкстры, вымостила дорогу в ад.


Кстати, если там добавить любое условие, — компилятор уже усомнится: а вдруг не все пути проходят через опасную формулу? И не станет вытаскивать бомбу из недр цикла в его шапку.
Перекуём баги на фичи!
Re[3]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 21:27
Оценка:
Здравствуйте, smeeld, Вы писали:

S>sizeof(int)==4, arch==x86_64, gcc -4.4.7


gcc-4.8.2 -O2
Перекуём баги на фичи!
Re[6]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 21:30
Оценка:
Здравствуйте, Marty, Вы писали:

M>А что произошло, раскрой интригу?


Компилятор обнаружил, что все пути в теле цикла проходят через i*миллиард, поэтому — если, конечно, программист не ССЗБ, — i лежит в диапазоне -2..+2, а следовательно, условие в шапке i<10 выполняется всегда. И поставил там true.
Перекуём баги на фичи!
Re[4]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 21:32
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Мой cl v14 все нормально переполнил и напечатал

M>Надо было написать, каким компилятором компилить

Неопределённое поведение — оно такое. Иногда оно кажется нормальным.
Перекуём баги на фичи!
Re[4]: каждый раз, когда вы пишете i++ + ++i...
От: smeeld  
Дата: 18.06.14 21:35
Оценка:
Здравствуйте, Кодт, Вы писали:


К>gcc-4.8.2 -O2


Может быть, результат gcc 4.4.7 c -O2 и -O3. 4.8.2 под рукой нет. Сори
Re[5]: каждый раз, когда вы пишете i++ + ++i...
От: Кодт Россия  
Дата: 18.06.14 21:46
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Может быть, результат gcc 4.4.7 c -O2 и -O3. 4.8.2 под рукой нет. Сори


А вы говорите, в седьмой шапочке сорок восьмой гусь... Пропал калабуховский дом!
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.