1. C++ / Говнокод #12806

    +20

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    int spectrumColor(float magn)
    {
    	if (magn != magn) return 0xFF000000;
    	if ((magn <= -FLT_MAX && magn >= FLT_MAX)) return 0xFF000000;
    	const float minRange = -95.0f;
    	if (magn > minRange && magn <= (minRange + 10.0f))
    		return blendColor(0, 0x00004f, (magn - minRange) / 10.0f);
    	if (magn > (minRange + 10.0f) && magn <= (minRange + 20.0f))
    		return blendColor(0x00004f, 0x50007b, (magn - (minRange + 10.0f)) / 10.0f);
    	if (magn > (minRange + 20.0f) && magn <= (minRange + 30.0f))
    		return blendColor(0x50007b, 0x990076, (magn - (minRange + 20.0f)) / 10.0f);
    	if (magn > (minRange + 30.0f) && magn <= (minRange + 40.0f))
    		return blendColor(0x990076, 0xd20040, (magn - (minRange + 30.0f)) / 10.0f);
    	if (magn > (minRange + 40.0f) && magn <= (minRange + 50.0f))
    		return blendColor(0xd20040, 0xf51f00, (magn - (minRange + 40.0f)) / 10.0f);
    	if (magn > (minRange + 50.0f) && magn <= (minRange + 60.0f))
    		return blendColor(0xf51f00, 0xffaa00, (magn - (minRange + 50.0f)) / 10.0f);
    	if (magn > (minRange + 60.0f) && magn <= (minRange + 70.0f))
    		return blendColor(0xffaa00, 0xfff966, (magn - (minRange + 60.0f)) / 10.0f);
    	if (magn > (minRange + 70.0f) && magn <= (minRange + 80.0f))
    		return blendColor(0xfff966, 0xffffff, (magn - (minRange + 70.0f)) / 10.0f);
    	if (magn < minRange) return 0xFF000000;
    	if (magn >= (minRange + 80.0f)) return 0xFFFFFFFF;
    	return 0xFF000000;
    }

    Вот так в одной говноподелке считается цвет столбцов спектра для визуализации аудио.

    Запостил: just_nameless, 25 Марта 2013

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

    • > if (magn != magn) return 0xFF000000;
      Вообщем то первая же строчка меня и убила :)
      Ответить
      • С первой строчкой как раз всё в порядке.
        http://ru.wikipedia.org/wiki/NaN
        Ответить
        • Ммммм... как тонко! Не знал таких подробностей! :(
          Ответить
        • Кстати, что интересно, с точки зрения соответствия Карри-Хорвада
          http://en.wikipedia.org/wiki/Intuitionistic_type_theory#Equality_type
          ничего не может не быть равным самому себе. Либо операция должна быть неопределена (надо бросать ошибку), либо должно равняться.
          Ответить
          • Теории для порядка в мире моделей математиков. В реальности исходя из потребностей может быть и не так.
            Ответить
          • А NaN это не число, поэтому оно подчиняться общим правилам не обязано ;)
            Ответить
            • Число, число, с плавающей запятой даже. ;)

              Т.е. если уж мы определили для него операцию, то оно должно быть числом, либо тогда уже не нужно было для него определять такую операцию. Смысл-то в том, что класс равенства нельзя определить так, чтобы выполнялось a != a, а что такое а - это уже в руке аллаха.
              Ответить
            • Собственно, мое понимание такое, что NaN это сериализованое сообщение об ошибке (когда еще можно получить NaN, как если не при возникновении ошибки). Просто кто-то сэкономил, и решил ошибку не выбрасывать... ну а экономия, как обычно, потянула за собой всякие нелогичные артефакты, типа нарушения фундаментальных свойств, таких как равенство.
              Ответить
              • > NaN это сериализованое сообщение об ошибке
                Именно так.

                > с плавающей запятой даже. ;)
                И далеко эта запятая уплыла? В нем нет ни мантиссы ни порядка, это сложно назвать числом.

                А насчет неравенства NaN != NaN - NaNы бывают разные, поэтому, чтобы не запутывать логику, все NaNы не равны друг другу.
                Ответить
                • Ну и что, что они могут быть разными. В примере мы ж сравниваем один и тот же, а не два разных NaN'а полученых из разных источников.
                  Ответить
                • ЗЫ. И, нет, это не причина неравенства. Причина, на сколько я понимаю, такая же, как и с null в сиквеле (где их бывает всего одна разновидность). Т.е. подразумевается, что "не равно" - эквивалентно ошибке, т.как если мы спрашивали "а равно ли?", то с нашей точки зрения, что ошибка, что отрицательный ответ - эквивалентны.
                  Но это создает противоречие, когда мы спрашиваем "а разные ли?" и вдруг получаем утвердительный ответ.
                  Ответить
                  • Все правильные числа правильны одинаково, все неправильные неправильны каждое по-своему.
                    Ответить
                  • можно еще NaN, как неопределенность, представить как число, которое постоянно изменяется, и поэтому когда мы сравниваем, то "первый" NaN уже не тот, что "второй".
                    Ответить
                    • А вообще, чтобы было правильно, то нужно было бы, чтобы для NaN == и != возвращал бы NaB (not a Boolean / not a bit). Тогда все было бы честно, но только, мне так кажется, людям бы больше обычные исключения в таком случае приглянулись.
                      Ответить
                      • и когда же НаБ истинен, а когда ложен?
                        Ответить
                        • НаБ не истинный и не ложный. Он как кот шредингера.
                          Ответить
                          • if(NaB) выполнится или нет?
                            Ответить
                            • да, выполнится или нет
                              Ответить
                            • if (NaB) то выполнится, а вот обе ветви ифа - нет ;)
                              Ответить
                            • > выполнится или нет
                              Если подойти к этой фразе формально - x || !x, что всегда истинно. Поэтому ответом будет "да".
                              Ответить
                      • А с другим NaB его сравнивать можно? ^^
                        Ответить
                      • Нет, исключения это неудобно.
                        Я хочу без исключений узнать, даст ли операция корректный результат. Сейчас способ есть - выполнить операцию и проверить результат на корректность. Всё это в режиме сопроцессора "не кидать исключения".
                        Ответить
                        • Ну так это потому, что так спроектировали оборудование и встроенное ПО. Это ж не значит, что именно так и нужно было сделать. Если бы исключения не были бы заплаткой, то наверное и отношение было бы другое.
                          Просто есть такая тенденция в проектировании: сначала спроектировать все так, как будто оно всегда работает безотказно, а потом думать, что же делать, когда не работает.
                          Ответить
                        • > хочу без исключений узнать, даст ли операция корректный результат

                          Вам в Go, товарищ, только одна проблема (для тебя): там есть сборщик мусора.
                          file, err := os.Open("file.go") // For read access.
                          if err != nil {
                          	log.Fatal(err)
                          }
                          Ответить
                          • Множественный возврат это православно
                            Ответить
                            • А возвращать кортеж или структуру уже не модно?
                              Ответить
                              • Удобство не то
                                Ответить
                                • std::tie
                                  Ответить
                                  • Он позволяет заводить переменные и сразу инициализировать множественным возвратом?
                                    Ответить
                                    • как ты заведешь в одной строчке две переменные разных типов? большинство языков такое не позволит
                                      но с++ позволит завести переменную одного типа - например, кортеж из типа1 и типа2, из которого ты потом получишь обе части - см. std::pair или более общий std::tuple

                                      std::tie связывает _существующие_ переменные
                                      Ответить
                                      • > как ты заведешь в одной строчке две переменные разных типов

                                        go может и типы выводит. Допустим, есть функция
                                        func doIt(x, y int) (int, error)
                                        (берёт 2 инта, возвращает int и error), стейтмент
                                        res, err := doIt(x, y)

                                        создаст две переменные разных типов. Можно ещё так:
                                        var res int, err error
                                        res, err = doIt(x, y)
                                        Без шаблонов как-то оно грустновато, хоть язык довольно интересный, и стандартная либа доставляет.
                                        Ответить
                                        • у ":=" семантика "создать", а у "=" - присвоить?
                                          почему они не подумали о тарасе?
                                          Ответить
                                          • > семантика "создать"
                                            Семантика немного сложнее (:= создаёт как минимум одну новую переменную, остальные может поменять, если они не в новом скопе), но суть такая. Тут каким-то местом замешан оберон, но я не знаю оный, и мне сложно судить.
                                            Ответить
                                      • > как ты заведешь в одной строчке две переменные разных типов?
                                        Вот я и говорю, как ты в этом крестоблядском убогом недоязыке, базирующемся на допотопном недоассемблере, заведёшь в одной строке две переменные разных типов, как
                                        file,err := os.Open("file.go")
                                        ?
                                        Ответить
                                    • Нет. И вывод типов auto отваливает
                                      Ответить
                                  • А ещё товарищи ругались, что он тормозной
                                    Ответить
                                • Там все равно внутри кортеж или структура.
                                  Ответить
      • В C++ ни в чём нельзя быть уверенным, ага. Особенно в C++.
        Ответить
    • А это не боян случайно?
      Ответить
    • Кстати, этот костыль фактически развернутый вручную цикл. Насколько такое решение рациональнее обычного цикла по массиву структур (структура состоит из значения амплитуды в дБ и соответствующего ей цвета)?
      Ответить
      • с данными константами и цикла по массиву не надо - можно сразу попасть пальцем в нужный индекс
        Ответить
        • То есть создать таблицу для всех возможных значений переменной magn? Я наверное чего-то не понял.
          В общем-то задача состоит в том, чтобы сделать преобразование амплитуды в цвет, как вот на этой картинке: http://upload.wikimedia.org/wikipedia/commons/c/c5/Spectrogram-19thC.png
          Ответить
          • index = floor(magn / 10);
            color = colors[index];
            Ответить
            • В этом случае будет скачкообразный переход цвета, а нужен плавный. Поэтом в этом говнокоде и сделана линейное смешивание в методе blendColor().
              Ответить
              • Там в blendColor какая-то константа забита - ею вызовы только и отличаются, вот ее и получить таким образом.
                Ответить
              • > Поэтом в этом говнокоде и сделана линейное смешивание в методе blendColor()
                Так передайте ему 2 цвета из таблички: [index] и [index+1] и (magn + 95.0) / 10.0 - index в качестве третьего аргумента.
                Ответить
            • Не забываем про -95 градусов и проверки:
              int index = floor((magn + 95.0) / 10.0);
              if (index < 0)
                  return что-нибудь;
              if (index > 8)
                  return что-нибудь;
              color = colors[index];
              Ответить
          • (unsigned)((magn - minRange) / 10.f) для значений magn в пределах [minRange, minRange + 80.0) даст сразу индекс в массиве из магического параметра {0, 0x00004f, 0x50007b, ...}
            2 случая меньше и больше этого отрезка останется рассмотреть отдельно

            как-то так
            Ответить
            • 0x00004f, 0x50007b - это цвета, аналогично тому, как они задаются в html. Я поясню. Нужно сделать, чтобы если magn был например от -95 до -85, то цвет выбирался путем линейного смешивания двух цветов - черного (0) и темно-синего (0x00004f). Чем ближе к -85, тем больше процент темно-синего, и тем меньше процент черного.
              Ответить
              • тебе тут уже всё разжевали, что тебе делать
                неужели сам не видишь никаких закономерностей в копипастных строчках?
                Ответить
                • да вижу я )
                  просто подумал, что меня неправильно поняли
                  Ответить
              • Да все уже это поняли ;) Такая хреновина отлично запиливается на табличке и небольшой арифметике. И не нужны тут 100500 ифов.
                Ответить
          • function VToColor (e: extended): TColor;
            var
              s: extended;
              r,g,b: extended;
            begin
              s := e*5;
            
              if s<1 then begin
                r := 0;
                g := 0;
                b := s;
              end else if s<2 then begin
                r := s-1;
                g := 0;
                b := 1;
              end else if s<3 then begin
                r := 1;
                g := 0;
                b := 3-s;
              end else if s<4 then begin
                r := 1;
                g := s-3;
                b := 0;
              end else begin
                r := 1;
                g := 1;
                b := s-4;
              end;
              Result := round (r*255) shl 16 + round (g*255) shl 8 + round(b*255);
            end;

            я тоже быдо и делаю ифами
            аж целых 5 ифов, дааа

            а, не, 4
            Ответить
            • Кстати, а сможешь сравнить по скорости и корректности с вот таким вариантом:
              function VToColor(e: extended): TColor;
              const colors = array [0..5] of integer = ($000000, $0000FF, $FF00FF, $FF0000, $FFFF00, $FFFFFF);
              var index: integer;
              begin
                e := e * 5;
                index := round(e);
                if index < 0 then
                  result := 0x000000
                else if index > 4 then
                  result := 0xFFFFFF
                else begin
                  e := e - index;
                  result := colors[index+1] * e + colors[index] * (1-e);
                end;
              end;
              Ответить
            • Вот это байтоебство, насколько понимаю, будет корректным:
              function VToColor(e: extended): TColor;
              const
                base = array [0..4] of integer = ($000000, $0000FF, $FF00FF, $FF0000, $FFFF00);
                mult = array [0..4] of integer = ($000001, $010000, -$000001, $000100, $000001);
              var
                index, offset;
              begin
                e := e*5;
                index := floor(e*5); // или как там его в паскале
                if index < 0 then
                  result := 0x000000
                if index > 4
                  result := 0xFFFFFF
                else begin
                  offset = floor((e - index)*255);
                  result := base[index] + mult[index] * offset;
                end;
              end;
              Ответить
              • Можно еще немножко побайтоёбить, и убрать еще одно флоатовское умножение:
                index := floor(e*(5*256));
                if index < 0 then
                  result := 0x000000
                else if index >= 0x500 then
                  result := 0xFFFFFF
                else
                  result := base[index shr 8] + mult[index shr 8] * (index and 0xFF);
                P.S. Кстати код Тараса очень даже неплох: если компилить его сишный аналог на gcc -O2, то моя последняя версия обгоняет его всего в 1.5 раза.
                Ответить
                • А если убрать проверки корректности, то во сколько?
                  Ответить
                  • На 100кк операций (цикл от 0 до 1, из времени вычтено время работы самого тестового цикла):
                    Код Тараса без модификаций - 2.6с.
                    Мой код с floor(e*(5*256)) - 1.8с.
                    Если убрать проверку index<0, время увеличивается до 3.4с. Вторая проверка на время не влияет.
                    Ответить
                    • Это как если убрать проверку, то время увеличивается? Приколы оптимизатора?
                      Ответить
                      • А вот хуй бы знал. Я сам не понимаю. Итоговый асм отличается тем, что убраны test и jg. Результат оба метода выдают абсолютно одинаковый (т.к. за диапазон я не вылезаю).
                        Ответить
                      • Отбой, походу какая-то хрень грузила проц в это время и вызвала отклонение. Прогнал еще десяток раз, обе проверки не влияют на время.

                        P.S. 1.7 секунд выполняется int index = (int)(e*(5*256)), остальное в пределах погрешности.
                        Ответить
                        • Надо избавиться от каста флоата в инт. Походу от него завиист все время исполнения.
                          Ответить
                          • Переходи на фиксед!
                            Ответить
                            • Ну это да, хорошая идея, если сами расчеты были бы на fixed'ах.
                              Ответить
                              • Но ынтерпрайзное быдло ненавидит фикседы.
                                Ответить
                      • Вот кстати о касте флоата в инт в gcc:
                        http://gcc.gnu.org/ml/gcc/2001-10/msg01039.html

                        Unfortunately, I've noticed that casting from float/double to int on i386 can cause large performance hits when this operations is used often.
                        Ответить
                  • Повысим градус байтоёбства (возможны краши при выходе за рабочий диапазон):
                    static inline int vtocolor2(float e) {
                        e += 1.0f;
                        int p;
                        memcpy(&p, &e, 4);
                        if (p & 0x40000000)
                            return 0xFFFFFF;
                        int index = ((p & 0x007FFFFF) * 5) >> 15;
                        return base[index >> 8] + mult[index >> 8] * (index & 0xFF);
                    }
                    Ответить
                    • Что за хуйня происходит в этом треде?

                      PS Зачем index >> 8 джва раза считать?
                      > mult[index >> 8] *
                      От этого умножения можно отказаться заменив индексы массива на сдвиги и хитрожопой маской поставив знак минус.
                      Ответить
                      • index>>8 одинхуй закешируется, я уверен, *5 тоже в lea превратится, ну насчёт маски приращения да, тут как-то ещё можно
                        Ответить
                        • >ну насчёт маски приращения
                          Я вам покушать принёс:
                          int a=(6-(index>> 8));
                          int m=-(a & 1);
                          int mi=(index & 0xFF);
                          return base[index >> 8] +(~m & mi) + (m & (mi<<((a-1)<<2)));

                          Примерно таким нехитрым образом можно вовсе отказаться от ветвлений и таблиц.
                          А то накал битоёбства недостаточно силён.
                          http://ideone.com/crluEj
                          Ответить
                          • После 0.4 бага - синий канал переполнился в зеленый.

                            Надо сложения поменять на ксоры. Тогда все будет хорошо.

                            P.S. По скорости получилось вдвое медленней http://govnokod.ru/12806#comment173275, по корректности - результаты совпадают.
                            Ответить
                            • >вдвое медленней
                              Не понял. У кого?
                              Это я не ради скорости, а скорее для лулзов и из любви к битоёбству.
                              Ответить
                              • Вдвое медленней моего.

                                > Это я не ради скорости, а скорее для лулзов и из любви к битоёбству.
                                Да понятно, можно и base так переписать, чтобы убрать массив.
                                Ответить
                                • И главное - сделать код максимально непонятным!
                                  >Вдвое медленней моего.
                                  Видать три-четыре такта из L1 и четыре на умножение быстрее чем полтора десятка элементарных операций.

                                  Это в былые времена умножение было мееедленым.
                                  Ответить
                      • Да умножение тут особо не мешает. У меня по крайней мере код с ним работал быстрее чем код со сдвигами (менял массив mult на массив shifts и тернарником менял знак во втором диапазоне).

                        > Зачем index >> 8 джва раза считать?
                        Ну если компилятор с этим не справится, то и остальной код будет таким говном, что проще переписать эту функцию полностью на асме.
                        Ответить
                        • Короче как ни крути, а по сравнению с кодом, в котором про оптимизацию и мыслей не было, больше полуторакратного ускорения не выжать.
                          Ответить
                          • >больше полуторакратного
                            можно чуть-чуть... думаю там где-нить десяток процентов можно выжать. 2 раза - потолок.
                            Просто размышлять над этим лень.
                            Ответить
                      • Ну вот так, кстати, можно попробовать:

                        const int base[5] = {0x000000, 0x0000FF, 0xFF00FF, 0xFF0000, 0xFFFF00};
                        const int shifts[5] = {0, 16, 0, 8, 0};
                        ...
                        return base[index >> 8] ^ ((index & 0xFF) << shifts[index >> 8];
                        Ответить
                        • Это слишком очевидно.
                          Мой вариант выше.
                          Знак допиливается так:
                          (~m & mi) | ((a==4)<<31)
                          Ответить
                    • Раз уж на то пошло, выкладываю код метода blendColor(), тут наверняка можно заняться байтоебством и оптимизировать.
                      int blendColor(int c1, int c2, float m)
                      {
                      	int mi = 255.0f*m;
                      	int imi = (~mi) & 0xFF;
                      	int r = (c1>>16&0xFF) * imi + (c2>>16&0xFF)*mi;
                      	r >>= 8;
                      	if (r > 255) r = 255;
                      	int g = (c1>>8&0xFF) * imi + (c2>>8&0xFF)*mi;
                      	g >>= 8;
                      	if (g > 255) g = 255;
                      	int b = (c1&0xFF) * imi + (c2&0xFF)*mi;
                      	b >>= 8;
                      	if (b > 255) b = 255;
                      	return 0xFF000000 | (b<<16) | (g<<8) | r;
                      }
                      Ответить
                      • Байтоебство для дошкольников.
                        Автор: Тарас Б.
                        Издательство: Говнокод.ру, 2013 г.
                        Язык: Русский
                        Год издания: 2013
                        Под редакцией Борманда.

                        Книга предназначена в первую очередь для обучения детей байтоебству на каникулах. Автором рассматривается реализация нетривиальных задач на примитивных битовых командах, а также вопросы тонкой оптимизации кода.
                        Издание может заинтересовать широкий круг читателей с различным уровнем подготовки.
                        Для детей дошкольного и младшего школьного возраста.
                        Ответить
                        • Где можно скачать в PDF?
                          Ответить
                          • Ссылка для скачивания видна только премиум пользователям.
                            Вы можете приобрести премиум-аккаунт.
                            Ответить
                        • У меня есть знакомый в министерстве образования. Можно пропихнуть как книжку рекомендуемую детям младших классов для самостоятельного внекласного чтения на канникулах.
                          Ответить
                      • А я блендил так:
                        result := c1 and $F0F0F0 + ((c2 and $F0F0F0 - c1 and $F0F0F0) * stage) shr 4.
                        stage - целое число от 0 до 16
                        правда стадий всего 16 и цвет выходит 12-битный, но всё равно очень оптимально получается

                        http://www.gamedev.ru/code/forum/?id=147090
                        Ответить
                        • Ну полноценный блендинг только на ммх/ссе можно запилить.

                          Ну а так да, для многих применений достаточно подобных упрощеных формул.
                          Ответить
                          • А в той теме на ММХ в итоге и запилили.
                            Ответить
            • В общем-то, никто не мешает использовать case Trunc(s) of вместо "целых четырех if-ов".
              Ответить
              • Копипасту это не уменьшит. Скорости это скорее всего не добавит (может оказаться слишком мало ветвей, чтобы свич стал эффективней пачки ифов). Лучше уж табличку, как я писал выше.
                Ответить
    • >> if (magn != magn) return 0xFF000000;
      А если тут перегрузка неравенства и что-то делается с magn? Или такого не бывает?
      Ответить
      • только если ты сделаешь #define float myuberclass
        операции встроенных типов нельзя перегрузить
        Ответить
    • Еще вариант — std::map<range_bound, key_value> в сочетании с lower_bound()
      Ответить
    • Встречается как-то 2 байта на говнокоде и один другому говорит:
      - Пошли ко мне домой.
      - Сейчас, только шапочек прикуплю.
      Ответить

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