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

    +36

    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
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    #include <iostream>
    #include <cmath> 
    
    struct Point3D
    {
            float x,y,z;
            Point3D () {}
            Point3D (float x, float y, float z) : x(x), y(y), z(z) {}
            Point3D& operator -= (const Point3D& p) { x-=p.x; y-=p.y; z-=p.z; return *this; }
            Point3D operator - (const Point3D& p) const { Point3D p2(*this); return (p2-=p); }
            Point3D& operator *= (const float f) { x*=f; y*=f; z*=f; return *this; }
            Point3D operator * (const float f) const { Point3D p2(*this); return (p2*=f); }
    };
    
    float Dot (const Point3D& p1, const Point3D& p2) { return p1.x*p2.x + p1.y*p2.y + p1.z*p2.z; }
    
    struct Face
    {
            Point3D            n;
            float              nc;
            float Dist (const Point3D& p) const { return Dot(p,n)-nc; }
    };
    
    int show_float(float src)
    {
            union
            {
                    int i;
                    float f;
            } u;
            u.f = src;
            return u.i;
    }
    
    float from_int(int src)
    {
            union
            {
                    int i;
                    float f;
            } u;
            u.i = src;
            return u.f;
    }
    
    template<typename T>
    T& operator<<(T& str, const Point3D& p)
    {
            str << std::hex << "Point3D(from_int(0x" << show_float(p.x) << "), from_int(0x" << show_float(p.y) << "), from_int(0x" << show_float(p.z) << "))";
            return str;
    }
    
    struct SPoint
    {
            Point3D p;
            bool DoCorrectFace(const Face& face)
            {
                    bool correct = true;
                    float j=1.0f;
                    Point3D np=p;
                    for (;;)
                    {
                            float ad = face.Dist(np);
                            if (ad<=0.0f)
                                    break;
                            correct=false;
                            np = p - (face.n*(ad*j));
                            j += 1.0f;
                    }
                    p=np;
                    return correct;
            }
    }; 
    
    using namespace std;
    int main()
    {
            cout << "Hello World!" << endl;
            SPoint spoint;
            spoint.p = Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0));
            cout << "Initial p:" << endl;
            cout << spoint.p << endl;
            cout << "Corrected:" << endl;
    
            Face f;
            f.n = Point3D(from_int(0x3d6cc83b), from_int(0x3f0e8841), from_int(0x3f5422bd));
            f.nc = from_int(0x41bac3dc); 
    
            bool result = spoint.DoCorrectFace(f);
            cout << spoint.p << endl;
            cout << "Done: " << result << endl;
            return 0;
    }

    говно в gcc
    g++ (rev5, Built by MinGW-W64 project) 4.8.1
    вывод в -O2 -DNDEBUG :

    Hello World!
    Initial p:
    Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
    Corrected:
    Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d1))
    Done: 0

    вывод в -O3 -DNDEBUG:

    Hello World!
    Initial p:
    Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
    Corrected:
    Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
    Done: 0

    внимание вопрос: может ли быть такое, что DoCorrectFace не изменил точку ни на бит, но вернул false? В gcc может!

    Запостил: TarasB, 23 Февраля 2014

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

    • Извините, ошибся маленько в описании
      -O2 -DNDEBUG и -O3 -DNDEBUG одинаково выдают хуйню (точка не изменилась после вызова), правильно точка обрабатывается вообще без -O
      Ответить
    • Point3D operator -
      Вот же говно!
      Point3D x, y, z;
      x - y = z;
      Ответить
    • Тарас стал юзать g++. Сначала вот кресты, потом MinGW, боюсь как бы до луникса дело не дошло.
      Ответить
      • показать все, что скрытоМинус.
        Ответить
      • Это не я юзаю.
        Это другой чел, который нарвался на баг в моём крестопроекте, которые не проявляется в студии.
        Неделю пытались понять, почему такая хуйня.
        Теперь поняли. Плавающийпитухпроблемы.
        Ответить
        • Важно ведь не как компилится и работает в студии, а что говорит нам стандарт.
          Сдается мне что там пахнет UB и gcc сделал тебе spoint.DoTrollFace(f).
          >>Это другой чел, который нарвался на баг в моём крестопроекте, которые не проявляется в студии.
          А-а. То есть по-прежнему непортируемый мс-онли код.
          Ответить
          • > А-а. То есть по-прежнему непортируемый мс-онли код.

            Мы вдвоём неделю искали, почему он оказался мс-онли.
            Ответить
        • >>Теперь поняли. Плавающийпитухпроблемы.
          http://artdesign21.narod.ru/image/1/ko_034.jpg
          Ответить
    • g++ (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1

      Все единички, баг повторить не удалось ;(

      P.S. gcc любит оптимизировать операции с флоатами оставляя их в регистрах сопроцессора (вспомни мой пост о sin(x) != sin(x). Возможно проблема в этом. Как экстендеды они не равны, а когда меняешь и суешь во флоат - ниче не меняется.

      UPD: А что делает DoCorrectFace?
      Ответить
      • > UPD: А что делает DoCorrectFace?

        Двигает точку p так, чтобы face.dist(p) стало <= 0.0f
        Проблема в том, что на бумаге написать, как надо двигать, очень просто. А чтоб на компе было ок - тяжело.
        Ответить
    • g++ 4.82. MinGW, win32. O2,O3.
      Hello World!
      Initial p:
      Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
      Corrected:
      Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
      Done: 0

      Может это винды. На луникс влом ребутить.
      Ответить
      • А чему равен show_float(ad) можешь показать? У меня выводит ровно 0.

        > На луникс влом ребутить.
        Вот на луниксе баг почему-то не получилось повторить.

        P.S. Есть вероятность, что от вывода баг пройдет, как и тогда с синусами. Что очень хреново ;(
        Ответить
        • если ты будешь выводить промежуточные переменные, то баг исчезнет)))
          именно поэтому мы неделю и не могли его поймать
          Ответить
          • > если ты будешь выводить промежуточные переменные, то баг исчезнет)))
            Тогда опция -ffloat-store по идее уберет баг.

            Но все-таки зря ты сравниваешь с 0. Имхо, стоит взять какой-то маленький эпсилон и сравнивать с ним. Если один объект воткнется в другой на тысячную часть пикселя - никто не заметит.
            Ответить
            • Ну да, я думал, что если внутри цикла f(x)<0.0f, то после сохраненя результата сохранится то, что f(x)<0.0f, а это оказывается, не так.
              Я-то думал, что уж на таких трюизмах-то можно забить на эпсилоны, а вот хуй, нельзя.
              Ответить
              • А вся жопа в том, что float и double в интеловском fpu нет. Он умеет только сохранять и выгружать флоаты, а вот все операции идут с 10 байтным числом. И компилятору влом гонять промежуточные значения через переменные, если ты явно не прикажешь ему.

                А вот в SSE флоаты и даблы настоящие, поэтому у меня баг не проявился ;(
                Ответить
                • На самом деле float внутри есть, надо только режим такой поставить. Кстати, ускоряет.
                  А есть ли портабельный какой-нибидь
                  __pitux_gcc_builtin_set_fpy_precision?
                  Ответить
                  • > На самом деле float внутри есть
                    Ну нету у FPU float'а, нету. Его можно только сэмулировать через выгрузку-загрузку в память. Что и делает -ffloat-store.

                    По идее портабельным решением будет volatile переменная. Компилятор не сможет убрать запись и чтение, и все будет норм.

                    P.S. Кстати баг, подобный твоему, когда-то был в пыхе. И он позволял специально подобранным числом повешать к хуям то ли парсер флоатов то ли конвертер флоата в строку.
                    Ответить
                    • Ставишь минимальную точность - и всё, внутри флоаты.
                      Ответить
                      • > Ставишь минимальную точность
                        А, ты вон про че... Я уже и забыл, что у штеудов такой флаг был...
                        Ответить
                        • Я ж говорю, флоат есть, специальный режим его ставит.
                          И я его ставил в дельфийском хулионе. Для ускорения типа.
                          Ответить
                          • Ну кроссплатформенно ты его не поставишь по понятной причине - на всех платформах кроме интела его тупо нет. Но можешь наебашить ifdef'ов и асма.

                            Кстати, вот очередной пример, когда глобальное состояние это очень хуёвая идея. Была бы эта точность в самой команде (например как в sse - разные инструкции для разной точности), а не в control word - таких проблем бы не было.
                            Ответить
                            • Полное говно.
                              С другой стороны, создавать десяток почти одинаковых команд - усложнять декодер, жизнь кодерам, лишние байты в коде команды, особенно когда надо выполнить пачку - алгоритм. Оно ж для программеров на асме - байтоёбов по-опеределению.

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

                              Смутно вспоминаю срачи, когда у интела была избыточная точность и она кому-то мешала, что они запилили сиё.
                              Ответить
                          • > Для ускорения типа.
                            На сколько процентов ускоряет? Есть статистика?
                            Ответить
                        • >у штеудов
                          Через год представляю картину: Тарас портирует хулион на ARM.
                          Джве недели постигали где баг армоблядском проце...
                          Ответить
                          • Так он уже вроде жаловался, что у старых армов вообще нет плавучки.
                            Ответить
                            • Так то старые. Вот у старых целеронов нету SSE...

                              О сколько нам открытий чудных
                              Готовит плавальный питух.
                              И опыт, сын багов коварных,
                              И гцц - кодеров друг.
                              Ответить
                          • Так код и так вполне себе годится для портирования на ведроид, только насчёт управления непонятно.
                            Ответить
                    • >> специально подобранным числом повешать к хуям то ли парсер флоатов то ли конвертер флоата в строку.
                      Интересно. А тут, на гкоде такое было?
                      Ответить
            • >опция -ffloat-store по идее уберет баг.
              Убирает.
              > стоит взять какой-то маленький эпсилон и сравнивать с ним
              +1
              Ответить
              • А volatile float ad помогает?
                Ответить
                • Не.
                  Зато int ad - да!
                  Ответить
                  • > Не.
                    O_o. Но почему?

                    А ну хотя. Оно же не влияет на вычисления, которые приводят к кривому ad. Там тогда всю цепочку вычислений надо через volatile прогонять...
                    Ответить
                    • Ответить
                    • А хз как оно для плавающих питухов, volatile вроде как рекомендация.
                      volatile float x,y,z; тоже. Мне кажется если ставить то там, что поставит КРЕСТ на скорости.

                      Последнее приводит только к изменению from_int(0xc166e2d0)) на from_int(0xc166e2d1)) - то есть как без оптимизаций, но done у меня и без оптимизаций false.
                      Ответить
                      • > volatile вроде как рекомендация.
                        Не, оно не рекомендация. Просто точность теряется на минусе в dist(). Вот туда если добавляешь volatile переменные - баг проходит. Но это не решение проблемы ;(

                        А проблема тут в том, что у интеловского FPU нет флоатов.
                        Ответить
                        • Ответить
                        • >что у интеловского FPU нет флоатов
                          Ну как это нет? Внутри нет, а чтобы сохранять/загружать из памяти есть.

                          Может printfы и конвертят таким образом в single precision? Мы же надеялись на то что volatile прогонит через память.
                          Ответить
        • >>А чему равен show_float(ad) можешь показать?
          gcc 4.82 без O
          На всех итерациях (штук 20): 32CFDDE8. На последней: B54DA3CE.

          g++ -Wall -O3
          Initial p:
          Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
          Corrected:
          B5551390
          Point3D(from_int(0x41c6940e), from_int(0x427352a6), from_int(0xc166e2d0))
          Done: 1
          Ответить
          • Ну вот, собрал по 32 битную рахитектуру - удалось повторить баг.

            > На всех итерациях (штук 20): 32CFDDE8. На последней: B54DA3CE.
            Именно так.
            Ответить
      • так это и есть баг
        точка НЕ изменилась, но возвращаемый результат ноль говорит, что точка была некорректной, то есть её таки меняли

        http://ideone.com/C5koEO
        зацените возвращаемый результат
        Ответить
        • >так это и есть баг
          Я понял. -O1 и выше там нормально.
          Ответить
        • >> но возвращаемый результат ноль говорит
          У меня Done: 0 всегда с любыми O (без принтов).
          Единственное отличие from_int(0xc166e2d0)) и from_int(0xc166e2d1)).
          Видать действительно в регистрах кешится, а принты каким-то образом очищают это.
          Ответить
          • > Видать действительно в регистрах кешится, а принты каким-то образом очищают это.
            Ну вспомни код, который я кидал давным-давно. Там два синуса давали разный результат. Если выводишь один из них - все равно багует. Выводишь оба - оп, и нету бага. Настоящий баг шрёдингера ;)
            Ответить
            • Помню. Взрывало моск. Особенно когда нет разъяснения.
              Ответить
              • Да, джве недели блядь чистили код крестоблядской версии хулиона от странных багов, не возникающих в Студии.
                Можно ли считать, что мой крестоскилл за эти недели вырос так, как он не вырос за год до этого?
                Ответить
            • Где тот код? Не смог найти.
              Ответить
              • Он где-то в комментах был. Сейчас попробую воссоздать.
                Ответить
              • http://govnokod.ru/12138

                Сорри, его не я постил. Я сраный плагиатор ;(
                Ответить
                • Зато не поленился подробно разобрать.
                  Комментарии с анализом получили больше плюсов чем сам ГК.
                  Ответить
      • наврядли. gcc достаточно консистентен в том как он рабоает на разных платформах. за что его и любят в портабельном программировании.

        ("На луникс влом ребутить.": ставь виртуалбокс, ставь какой дебьян без гуя (или с xfce). 512М памяти и 20Г диска хватает за глаза. если хочешь совсем свежак ставь дебьян sid (aptosid), но его надо апдейтить часто (как минимум раз в месяц). и он ломается иногда когда миграции происходят - https://release.debian.org/transitions/ - но меня как вторичная/третичная система устраивает.)

        надо epsilon добавить на строке 64 попробовать.
        Ответить
        • > достаточно консистентен в том как он рабоает на разных платформах
          Ну вот у меня 64 битная ось. И, как я понимаю, наличие SSE на такой платформе подразумевается. Поэтому gcc собрал код через sse, и точность выше флоата не подскочила - бага нет.

          У Тараса SSE нет (целерон 600), все считается на FPU, и проявляется баг.
          Ответить
          • ну поэтому я же и говорю что в коде есть один как по мне очевидный баг в строке 64: для сравнения нужно epsilon использовать.

            да и вроде же gcc SSE без пинка не подключает. по крайней мере раньше надо было -march/-mcpu задавать - просто -О не хватало.
            Ответить
            • А на 64 битке SSE походу подразумевается. По крайней мере первое.

              На 32 же по дефолту стоят весьма консервативные march/mcpu. Что-то типа 386 или 686. Поэтому там и надо указывать...
              Ответить
              • Интуиция не подвела. Я потому сразу на win32 и стал пробовать - чтоб всё как у Тараса.
                Ответить
              • да. сам уже в odjdump -d увидел. (даже с -O0.)

                к сожалению у меня для 32бит нет окружения - с -m32 ничего не компилится вообще.
                Ответить
                • > к сожалению у меня для 32бит нет окружения - с -m32 ничего не компилится вообще.
                  Аналогично, надо бы установить.
                  Ответить
    • gcc 4.72
      unknown software exception (0xc0000096) в приложении по адресу 0x00405025.
      ВНЕЗАПНО
      Ответить
      • В -O2?
        Ответить
        • Да везде. Старый g++ видать как-то криво запускается. Другие проекты такая же дрочь.
          Ответить
    • Ответить
    • Суть треда:
      God made natural numbers; all else is the work of man
      Leopold Kronecker

      http://cache.desktopnexus.com/thumbnails/695809-bigthumbnail.jpg
      Ответить

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