1. Си / Говнокод #8689

    +111

    1. 1
    2. 2
    3. 3
    for(x = 1; x; x += x)
      if(!(((e*x)%m)/t))
      { x = d; break; }

    Недавно прислали с вопросом: "Тут что-то поломалось, надо исправить... Поможешь?"

    Запостил: TarTar, 30 Ноября 2011

    Комментарии (45) RSS

    • весьма странный алгоритм... чего?
      Ответить
    • > for(x = 1; x; x += x)
      это пять!
      Ответить
      • Это два в степени.
        Ответить
      • даите два
        Ответить
      • Перебор степеней двойки, при этом тут неявно используется тот факт, что x принадлежит типу mod 2**32 (модульный тип, при переполнении значение сдвигается по циклу, а не выбрасывает ошибку).
        Ответить
        • Спасибо, я понял.
          Ответить
          • В общем, это как раз не говно, а прикольная фишка.
            Ответить
            • Использовать переполнение как условие выхода из цикла looks like dirty hack.
              Ответить
              • Если ты используешь модульный тип, то использовать переполнение - не хак, а фича.
                А, это же КРЕСТЫ, тут нет модульных типов...
                Ответить
                • долго пытался понять, что за ноу-хауъ такое - модульные типы
                  оказалось банально
                  "Таким образом, модульные типы Ада соответствуют целочисленным беззнаковым типам в других языках программирования (например: Byte, Word... - в реализациях Паскаля; unsigned short, unsigned... - в C/C++)."

                  я верно понял, что в аде целое число либо знаковое, либо "модульное"?
                  Ответить
                  • Нет, с чего ты взял?

                    Хорошо, что я успел ответить, а то чуть новый миф не родился ("ололо, в Аде нет беззнаковых типов с контролем переполнения").

                    Помню, я на гдрушечке сказал, что в Паскале ГСЧ инициализируется текущим временем при помощи функции Randomize, так там один тип сразу же вывел из этого, что стандартный паскалевский ГСЧ нельзя инициализировать своим значением.

                    Вообще логика крестушков поражает.
                    Скажешь им, что паскалевский case (аналог switch) позволяет указывать диапазоны и перечисления - они в ответ заявляют, что он не умеет оптимально искать число и что там делается тупо цепочка else if. Да, тоже на гдрушечке.

                    Сегодня один хрен бездоказательно вывел, что якобы Дельфи не умеет убивать ветки, которые никогда не выполнятся. Да, тоже на гдрушечке.
                    Ответить
                    • > Вообще логика крестушков поражает.
                      Да это же не типичные крестушки, а просто типичные полуебки. 95% процентов всего этого бессвязного лепета решается прочтением документации, где многа букав, да. Такие говноспоры можно решить парой встречных вопросов по поведению крестов и они сразу поджимают хвосты, потому что в своем любимом инструменте аналогично слабо разбираются.
                      Ответить
                    • > с чего ты взял
                      с какого то первого попавшегося мануала, который мне на пальцах рассказал, зачем в аде отдельная сущность с отдельным названием "модульный целочисленный тип"
                      http://www.ada-ru.org/V-0.4w/part_1/ch_02.html
                      еще цитата, оттуда же
                      "Стандарт Ada95 разделяет целочисленные типы на целые числа со знаком и модульные типы. По существу, модульные типы являются целыми числами без знака. Характерной особенностью таких типов является свойство цикличности арифметических операций."

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

                      предугадывая твои вопросы - мне не сложно в С++ написать микрокласс над стандартным типом, который бы отслеживал свои переполнения без ассемблера, а для некоторых диапазонов (- 2 ** i .. 2 ** i, где i <=6, 14, 30, 62) оверхед был бы даже наноскопическим, но что то как то не было нужды
                      Ответить
                      • > По существу, модульные типы являются целыми числами без знака.

                        Непонятно. Можно задать тип с контролем переполнения с любым диапазоном. Хоть со знаком, хоть без, хоть вообще от -5 до +9000.

                        > контроль переполнения на каждый чих - оверкилл какой то
                        > а для некоторых диапазонов (- 2 ** i .. 2 ** i, где i <=6, 14, 30, 62) оверхед был бы даже наноскопическим

                        Так оверкилл или наноскопия?
                        Зато не надо проверять контроль диапазона для индекса массива, если переменная, которой итерируем, принадлежит типу, являющемся диапазоном массива.
                        Контроль ошибки переполнения меня спасал не раз, если что.

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

                            2 разряда на знак? Нафига. Что-то был в Окамле такой косяк, помнится.
                            В Аде тип integer работает без этого.

                            > но этот оверкилл был намеренно заложен в аду, для надежности

                            Это другой подход к проверкам. И иногда он даёт ускорение.
                            for i in A'Range loop
                            s:=s+A(i); // тут не делается проверка на вхождение, так как итак i принадлежит типу A'Range
                            end loop;

                            Кстати, в Дельфи так же. И тут Пушков снова обломался, когда сказал, что в Дельфи делается проверка на вхождение в диапазон массива. Так вот хрен. Если
                            a: array [Smth] of integer;
                            i: Smth;
                            То в
                            a[i] проверка не делается.
                            Но Пушков, очевидно, проверял для i: integer;
                            Что делать, крестушки не умеют использовать на всю катушку особенности системы типов в паскалевом семействе.

                            > для справки - в аде можно создать тип из границ, известных только во времени выполнения?

                            Да, конечно. И массивы неизвестной длины, аллоцирующиеся на стеке. Иначе как будут работать шаблонные модули, инициализируемые параметрами, полученными при выполнении?
                            Ответить
                            • работать с переполнением можно по разному
                              проверять регистров флагов (чего в С/С++ без использования ассемблера напрямую я не знаю как сделать) - возможно не на каждом процессоре этот регистр есть вообще, или просто выделить еще один разряд рядом со знаком, тогда 00,11 будут означать валидные +/- числа, а 01,10 - переполненные +/- числа

                              > a[i] проверка не делается
                              компилятору приходится всего лишь каждый раз вычислять offset из передаваемого аргумента, в отличие от C/C++, который перекладывает эти задачи на программиста
                              для статических проверок "из коробки" в С/С++ есть только упрощенный вариант с
                              typedef enum { elem0 = 0, elem1, elem2, elem3 } elem_idx_type;
                              int a[elem3 + 1];
                              elem_idx_type i = elem2;
                              a[i] - аналогично не сможешь выйти за границы
                              конечно не надо забывать, что для си что a[i], что *(a + i), что i[a] одно и то же - отдаст ячейку по смещению от адреса a и его не будут парить границы - и иногда это как раз удобно, есть такой трюк

                              а вот если в дельфи объявлено a: array [Smth] of integer;
                              компилятор ругается при a[200], если 200 не входит в диапазон?
                              Ответить
                              • > возможно не на каждом процессоре этот регистр есть вообще

                                Ну не знаю, ГНАТ, работающий ерез кроссплатформенный ГЦЦ, это не остановило.

                                > компилятору приходится всего лишь каждый раз вычислять offset из передаваемого аргумента

                                Ну и что? Лишь бы не программа.

                                > а вот если в дельфи объявлено a: array [Smth] of integer;
                                компилятор ругается при a[200], если 200 не входит в диапазон?

                                Ругается, но я не помню, в виде ошибки или предупреждения.
                                Ответить
                                • стало интересно
                                  http://en.wikipedia.org/wiki/Overflow_flag
                                  Instructions such as multiply and divide often leave the flag undefined, or affected by the last partial result.
                                  так что врядли адовский компилятор опирается на флаги состояния процессора, поэтому у него остается два пути
                                  1) для результата умножения A * B выделять место размером size(A)+size(B), отправлять на процессор делать умножение и потом смотреть влез ли результат в пользовательский диапазон - дешево, быстро, но ограниченно
                                  2) попытаться в обход CPU сделать умножение по своим алгоритмам, в процессе определив переполнение - в принципе, вполне посильная задача, например, с помощью всем известного shift and add (и, фактически, на этот способ намекают ограничения по размерам целых типов в стандарте, который я нашёл)

                                  generic programming в рантайме это бывает и неплохо, конечно
                                  как ада разбирается с тем, что требуется вызвать конкретный метод у объекта, передаваемого как private?
                                  Ответить
                                  • Умножение сохраняет результат в eax:edx, на этом основана работа встроенных в Аду фиксированных типов. Умножать в обход процессора не нужно.

                                    Передавать в шаблоны "структура, у которой есть поле a", нельзя. Можно передавать "тип, для которого определены Get(T,a) и Set(T,a)".
                                    Ответить
                                    • >Умножать в обход процессора не нужно.

                                      Я вот что-то не пойму. Язык Ада, он тобой в одних случаях классифицируется как высокоуровневый язык (в отличие от КРЕСТОВ синтаксис которых во многом завязан на низкоуровневость).
                                      В других же, Ада напрямую привязана к процессорной реализации умножения.
                                      Ответить
                                      • Глупее ниего не мог спросить?
                                        Синтаксис Ады ни к чему не привязан.
                                        Привязана реализация.
                                        Будет другой проц - будет другая реализация.
                                        Ответить
                                        • >Умножение сохраняет результат в eax:edx, на этом основана работа встроенных в Аду фиксированных типов.

                                          Из этого предложения я сделал вывод, что работа диапазонных типов Ады основана на специфике умножения в x86.
                                          Ответить
                                          • Ну на самом деле так быть не может, ведь Йаду очень часто используют в военных девайсах.
                                            Ответить
                                            • Я знаю. Потому и спросил, ибо звучит как-то бредово - типы Ады базируются на eax:edx.
                                              Ответить
                                          • Не работа, а реализация в компиляторе под PC.
                                            Ответить
                                    • вот они ограничения рантайм генериков
                                      где то очевидные плюсы, а затем минусы, перекрывающие все плюсы
                                      Ответить
                                      • Расскажи про ограничения.
                                        Это каким извращённым мозгом надо обладать, чтобы из описания потрохов одной реализации сделать вывод, что всё гвоздями прибито к этой реализации?
                                        Давайте, я тоже потроллю.
                                        В C под x86 сложение целых делается через add eax,edx (ну или другие два регистра), всё, значит C гвоздями прибит к x86, потому что его сложение опирается на архитектуру х86.
                                        Ответить
                                        • что то у тебя какой то асимметричный ответ, про регистры ты другому отписывайся, как по мне, так это правильно, что используется ЦПУ, а не велосипед (меня еще интересовал этот вопрос в свете целых типов длиннее возможностей архитектуры, я узнал ответ и без тебя)
                                          преимущества компайл-тайм шаблонов С++ - если тебе передали тип T, то ты с ним можешь вертеться как хочешь - хочешь обращайся к его полям, хочешь вызывай методы, хочешь используй объявленные в нем типы, константы, енумы - всё, до чего дотягиваются руки, хочешь наследуйся от него, объявляй на его основе другие типы
                                          компилятор всё съест и если где то не срастётся - будет тебе жаловаться, потому что он разворачивает это всё и затем пытается взлететь
                                          недостатки также очевидны
                                          я почему спросил - к рантайм/гибридным дженерикам в разных языках разный подход, и в этом свете подход ады не выглядит самым удобным
                                          тупо запретить любые телодвижения в влево/вправо - на тебе объект-черный ящик и крутись как хочешь. Если запрещено работать с объектом как с объектом, а разрешено с ним работать только как с куском памяти известного размера, то такой дженерик не намного отличается от передачи в виде аргументов void * и size_t оного - сделать контейнер элементов произвольного типа в рантайме, предоставляя доступ к каждому из элементов, методы его роста, можно даже на С - ты же на это ссылался, что можно на стеке создавать массивы переменной длины

                                          если бы ты раскрыл в чем суть
                                          > "тип, для которого определены Get(T,a) и Set(T,a)"
                                          может моё мнение и изменилось бы
                                          Ответить
                                          • Суть в том, что в Аде можно проводить над типом T только те операции, которые указаны в заголовке шаблона.
                                            Причём под операциями подрузумеваются исключительно процедуры и функции (бинарные операторы тоже к ним относятся). А вот операция взятия поля с именем a к ним, увы, не относится, поэтому, если тебе это надо, ты можешь только передавать туда GetA и SetA.
                                            И это не совсем как в Си, потому что передаваемый в шаблон функции могут инлайниться.
                                            Ответить
                                      • Ой, в письме не увидел про T.a. Это тоже можно и в рантайм впихнуть. Всё равно от рантайма зависят только константы, компилятор всегда знает, массив чего передаётся в модуль - массив целых или вещественных. Компилятор может не знать только диапазон.
                                        Да, ты скажешь, что это на крестах элмулируется, ну так это да, тьюринг-полнота.
                                        Ну а чего ты такого ожидал от статически типизированного языка?
                                        Да, так вот насчёт T.a.
                                        Просто этого нет в концепции. Да и вообще, это не инкапсулятивненько.
                                        Ответить
    • >x = d;
      d в цикле не вычисляется.
      что-то тут не чисто.
      Ответить
    • Форматни кодца.
      Ответить
    • if(!(((e*x)%m)/t)), я даже боюсь предположить при каких условиях выполнится этот иф.
      Ответить
    • Очень похоже на первый этап теста Миллера-Рабина.
      Ответить
    • блеать
      Ответить
    • > Тут что-то поломалось

      мой мозг.
      Ответить

    Добавить комментарий