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

    +142

    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
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    static char months [] = "JanFebMarAprMayJunJulAugSepOctNovDecGlk";
    static char dows [] = "SunMonTueWedThuFriSatEar";
    
    
    int dd [] =
    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    void gen_http_date (char date_buffer[29], int time) {
      int day, mon, year, hour, min, sec, xd, i, dow;
      if (time < 0) time = 0;
      sec = time % 60;
      time /= 60;
      min = time % 60;
      time /= 60;
      hour = time % 24;
      time /= 24;
      dow = (time + 4) % 7;
      xd = time % (365 * 3 + 366);
      time /= (365 * 3 + 366);
      year = time * 4 + 1970;
      if (xd >= 365) {
        year++;
        xd -= 365;
        if (xd >= 365) {
          year++;
          xd -= 365;
          if (xd >= 366) {
            year++;
            xd -= 366;
          }
        }
      }
      if (year & 3) {
        dd[1] = 28;
      } else {
        dd[1] = 29;
      }
    
      for (i = 0; i < 12; i++) {
        if (xd < dd[i]) {
          break;
        }
        xd -= dd[i];
      }
    
      day = xd + 1;
      mon = i;
      assert (day >= 1 && day <= 31 && mon >=0 && mon <= 11 &&
          year >= 1970 && year <= 2039);
    
      sprintf (date_buffer, "%.3s, %.2d %.3s %d %.2d:%.2d:%.2d GM",
          dows + dow * 3, day, months + mon * 3, year,
          hour, min, sec);
      date_buffer[28] = 'T';
    }

    Делать имена месяцев и дни недели одной сишной строкой, чтобы потом выводить оттуда по три символа через sprintf, считая оффсет умножением на 3 т.к. имена месяцев и дней недели влазят в три символа
    https://github.com/vk-com/kphp-kdb/blob/ce1ac4fbde2d3b546936ad07d6a748958f6d2198/net/net-http-server.c#L664

    http://roem.ru/2013/07/20/kphp76561/
    >ВКонтактовские "олимпиадники"-чемпионы ACM разработали крайне интересную высоконагруженным сайтам технологию.

    Хреновые какие-то олимпиадники попались, раз неосилили http://ideone.com/IfvBgi

    Запостил: j123123, 09 Марта 2014

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

    • показать все, что скрытоВъебал минус.
      Ответить
    • Меня смутило
      assert (day >= 1 && day <= 31 && mon >=0 && mon <= 11 &&
      year >= 1970 && year <= 2039);

      Про 1970 очевидно, начало юникс-времени и вселенной. А что у нас с 2039 годом?
      Ответить
      • Полагаю, что это связано с тем, что
        > Самая поздняя дата, которая может быть представлена таким форматом в стандарте POSIX — это 03:14:07, вторник, 19 января 2038 года по Всемирному времени (UTC).
        https://ru.wikipedia.org/wiki/Проблема_2038_года

        Проверка, впрочем, в таком случае становится хоть и логичной, но некорректной.
        Ответить
    • Это оптимизация. Одна строка занимает на двенадцать '\0' меньше массива из тринадцати строк.
      Ответить
      • В варианте http://ideone.com/IfvBgi нулей нет, байты(буквы) там идут сплошным куском
        http://ideone.com/GAJ1j1
        Ответить
        • Нихуясебенезнал
          Пойду стандарт полистаю
          Ответить
          • А че такого? Там же четко написано – ТРИ. Четвертый ноль просто не лезет.
            Ответить
            • Я удивился тому, что двумерный массив лежит в сплошном куске памяти. Как же я деградировал с этими STLами и boostами...
              Ответить
              • > лежит в сплошном куске памяти.
                Именно поэтому все размерности, кроме самой первой, должны быть константами...
                Ответить
                • ну вот, в облаке нельзя сохранить двумерный массив, пичалько...
                  Ответить
    • Мне понравились return code'ы в функции ниже и то, что int dd[] используется и в gen_http_time, и в gen_http_date, да и вообще никто не мешает дернуть его extern'ом.

      https://github.com/vk-com/kphp-kdb/blob/ce1ac4fbde2d3b546936ad07d6a748958f6d2198/net/net-http-server.c#L735
      Ответить
    • я так понимаю, олимпиадники-чемпионы ACM уже просто не способны писать код, который понятен простым смертным c первого взгляда?
      Ответить
      • Это как бодибилдинг. Мясо есть, а вагоны не разгружает.
        Ответить
    • > if (year & 3) {
      dd[1] = 28;
      } else {
      dd[1] = 29;
      }

      а что, 2100 - високосный?
      а, ну да, он же не в диапазоне, значит можно хуй забить
      АЦМ-логика, да
      Ответить
    • Да нормальный код - на первый взгляд вроде всё корректно. А в датах всегда такое говно будет - это их специфика.
      И байтоёбства преступно мало.

      Может тут можно было ускорить поиск:
      for (i = 0; i < 12; i++) {
          if (xd < dd[i]) {
            break;
          }
          xd -= dd[i];
        }
      Ответить
      • Править глобальный массив с длинами месяцев - это корректно? ;)
        Ответить
        • Вот как-то так без правки глобального массива (в самом массиве в феврале должно быть 29 дней):
          // если год невисокосный и месяц больше февраля - добавляем единичку
          if (!is_leap_year && xd >= 31 + 28)
              ++xd;
          Ответить
          • P.S. Кстати, никто не считал, какой импульс нужно сообщить земле, чтобы навсегда избавиться от високосных годов?
            Ответить
            • >Навсегда
              Тогда нужно ещё и силу трения отменить вдобавок и всю термодинамику.
              Ответить
              • Ну там можно периодически корректировки устраивать, если погрешность все-таки накопится ;)
                Ответить
            • За последние полдня в году Земля пролетает 5.5 млн километров.
              Ответить
              • Так не обязательно же менять именно орбитальную скорость. Можно ведь и вращение вокруг своей оси чуть-чуть притормозить, лишь бы соотношение выровнялось...
                Ответить
                • По одной минуте прибавить к каждому дню.
                  Ответить
                  • Не вариант... Поплывет привязка к восходам\закатам.

                    Тут же именно само соотношение между периодом обращения вокруг солнца и вокруг своей оси забагованное.
                    Ответить
                    • Так в том и суть, надо так ударить по касательной, чтобы сутки удинились приблизительно на минуту.
                      Ответить
                      • А, ну да, тогда согласен. По идее импульс надо приложить в двух диаметрально противоположных точках на экваторе по касательной. Чтобы притормозить вращение вокруг оси на ту самую минуту.
                        Ответить
                        • Нужно 3.78 * 10^26 Джоуль энергии
                          Ответить
                          • О, круто. А как считал? Через кинетическую энергию вертящегося шара?
                            Ответить
                            • Да.
                              (2r5)*5.97e24*6371e3^2
                              9.69281e37
                                 a=:-:(*:(2*o.1)%(84600))*9.69281e37
                                 b=:-:(*:(2*o.1)%(84660))*9.69281e37
                                 a-b
                              3.78781e26
                                 c=:a-b
                                 c%(3600*150e15)
                              701446
                              Ответить
                        • Это потребление всего мира за 700000 лет если потреблять будут как в 2008 году.
                          Ответить
                          • Или миллиард водородных бомб ;)

                            (Вики гласит, что полная энергия взрыва царь-бомбы оценивается в 2,4·10^17Дж).
                            Ответить
            • В СССР был проект вечного календаря
              http://lib.rus.ec/i/23/299223/p47.png
              А так у нас всего 14 разных календарей.
              Ответить
              • Каждый декабрь==31 день, за счет введения праздничного дня+поправка+-1 день в июне, не считая 30 дней в каждом месяце. Тонко.
                Ответить
                • http://webplus.info/images/wpi.images/atr314_001.jpg
                  Ответить
                  • Еще круглый календарик вроде был.
                    Ответить
                  • Ну, что сказать. Люди тогда были не ленивы, это большой плюс. Кто бы сейчас стал возиться с этим?
                    Ответить
                    • А че там возиться? Эта табличка элементарно строится.
                      Ответить
                      • Я хотел сказать, что люди предпочитают покупать готовый настенный годовой календарь, чем самостоятельно производить расчеты.
                        Ответить
              • Ещё в СССР был проект Революционного календаря. Как по мне, так полумера, Французский республиканский календарь решал проблему с днями недели и вычислением даты по номеру дня, поместив «лишние» дни в конец года.

                http://ru.wikipedia.org/wiki/Французский_республиканский_календарь
                Ответить
                • 9 термидора
                  Ответить
                  • 309 день года, 9 месяц, 9 день месяца, 9 день недели.
                    256, кстати был бы 16 прериаля.

                    Ещё в плюсах — фиксированный день недели. Больше одного календаря не понадобится, да и тот не нужен, если можешь считать в уме на уровне 5 класса.
                    Ответить
        • oh shi~
          Ответить
      • > Может тут можно было ускорить поиск
        Ну как вариант - двоичный поиск в сложенном заранее массиве. Или даже захардкоженный поиск в духе:
        if (xd < 181) {
            // январь - июнь
            if (xd < 90) {
                // январь - март
                // ...
            } else {
                // апрель - июнь
                // ...
            }
        } else {
            // июль - декабрь
            // ...
        }
        Или может быть даже лукап из массива в 365 ячеек... Х.з., что из этого будет быстрее...

        P.S. Но на самом деле, дат в таком формате в выхлопе сервера не так уж много, и всё это байтоёбство мало что даст в плане общей производительности...
        Ответить
        • > даже лукап из массива в 365 ячеек.
          > двоичный поиск в сложенном заранее массиве
          Думал про оба. Таблица - неплохо, но относительно большая.
          Двоичный поиск для малых таблиц зачастую медленее, потому что тупой цикл выполняется быстрее за счёт его тупости и последовательного обращения к памяти.

          Как насчёт компромисного варианта: перебирать с шагом 2, а если превысили, то выбирать из 2-х предыдущих.
          Ответить
          • Ну вот те хардкодные ифы, которые я привел, будут явно быстрее, чем двоичный поиск с циклом т.к. здесь нет ветвлений на поддержание самого цикла.

            Мне кажется, что все-таки таблица на 366 ячеек будет самым эффективным решением - нет переходов, максимум один cache miss на выборку.
            Ответить
      • 13 месяцев и 8 дней недели это тоже корректно? :)

        Да, в расчетах то 7 и 12, но в массивах с именами то 8 и 13...
        Ответить
    • По поводу разделителей. Я тоже ленюсь набирать массивы:
      '1','2','3' - очень напрягает кучу кавычек набирать
      потому частенько делаю '1,2,3'.split(',')
      Ответить
      • Вам нужен Perl:
        qw(1 2 3)


        http://ideone.com/tTFkXf
        Ответить
        • Ruby же. %w(1 2 3)
          http://ideone.com/uUFA4K
          Ответить
          • Да уймитесь наконец. Руби, пёрл - да ну их нахер.
            Никогда не понимал этого - выбор языка из-за какого-то малозначимого сахарка.
            В любом популярном и не очень яву можно сделать себе функцию:
            qw("1 2 3")
            Ответить
            • А в сишке и крестах, по идее, даже макрос qw(1,2,3).
              Ответить
            • Суть не в том что язык выбирают из-за малозначимого сахара, а в том что уже выбрав язык смешно смотреть на убогие проблемы языков не имеющих этого сахара, поэтому и сложно удержаться от комментария.
              Ответить
              • И как часто в коде на руби требуются длинные захардкоженные массивы из слов?
                Ответить
                • показать все, что скрытоВстречный вопрос: как часто ты опрокидываешь себе шкалик спермы за воротник?
                  Ответить
                • Я встречал такие массивы в web-api. Например была валидация входящих параметров, где нужно было принять слово из набора -- как раз удобно.
                  Ответить
              • >смешно смотреть на убогие проблемы языков не имеющих этого сахара
                Да. Кодеры всего мира которых НЕ пишут на руби сейчас неистово негодуют, и выбрасывают свои языки, попутно переучиваясь на ruby потому что не могут записать массив через пробелы.
                Проблемы подобного рода исключительно в голове у программиста. А ведь изначально Elvenfighter зеленым написал...
                Ответить
            • > В любом популярном и не очень яву можно сделать себе функцию:
              qw("1 2 3")

              только она не отработает при компиляции
              Ответить
              • > только она не отработает при компиляции
                Засунь ее результат в глобальную статическую переменную. Всем пофиг на эти несколько наносекунд при старте. Да и один хрен в пёрле и руби эта самая "компиляция" происходит примерно в тот же момент (или они уже научились сохранять байткод аля питон?).
                Ответить
          • Common Lisp:
            #(1 2 3)

            :/

            Баш:
            (1 2 3)
            Ответить
            • Ох, про J я то и забыл:
              1 2 3
              Ответить
            • С числам везде просто, /pi про список строк/символов говорит
              Ответить
              • Ну в шелле это список строк.
                В Лиспе #(a b c) будет массивом строк.
                В J все данные - массивы, интерпретация будет зависеть от читателя.

                В большинстве языков не так уж и просто - нужно писать никому не нужные запятые.
                Ответить
                • а если я хочу строки с пробелами
                  в лиспе хардкодные литералы строк вроде не особо нужны, там символы есть, имхо они более подходят по философию языка.
                  Ответить
    • Байтоёбили-байтоёбили и невыбайтоёбили...
      // 10кк тестов
      
      gen_http_date(buf, t);
      0m14.895s
      
      strftime(buf, 256, "%a, %d %b %Y %T GMT", gmtime(&t))
      0m10.371s
      Ответить
    • А тут мы вставленный sprintf-ом последний нулевой байтик вручную перезаписываем на 'T' :
      sprintf (date_buffer, "%.3s, %.2d %.3s %d %.2d:%.2d:%.2d GM",
          dows + dow * 3, day, months + mon * 3, year,
          hour, min, sec);
      date_buffer[28] = 'T';

      Не проще ли сделать возвращаемый буфер на один байт больше?
      Ответить
      • > Не проще ли сделать возвращаемый буфер на один байт больше?
        Байтоёбы, чо. Экономят на спичках в многомегабайтном бинарнике.
        Ответить
    • и еще по поводу длинных данных: а как жеж хранить ресурсы вместе с исполняемым кодом? ;)
      Ответить
      • Вкомпиливать в виде статических сишных массивов же. Надежный, производительный и кроссплатформенный приём ;)
        Ответить
    • 13-й месяц называется "Glk". К чему бы это?
      Ответить

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