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

    +4

    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
    #include <inttypes.h>
    
    auto a(auto b) __attribute__ ((noinline));
    
    auto a(auto b)
    {
        return b*1.5;
    }
    
    double test1(double in)
    {
      return a(in);
    }
    
    uint64_t test2(uint64_t in)
    {
      return a(in);
    }
    
    
    /*
    https://godbolt.org/z/6ZQAnv
    
    auto a<double>(double):
            mulsd   xmm0, QWORD PTR .LC0[rip]
            ret
    test1(double):
            jmp     auto a<double>(double)
    auto a<unsigned long>(unsigned long):
            test    rdi, rdi
            js      .L5
            pxor    xmm0, xmm0
            cvtsi2sd        xmm0, rdi
            mulsd   xmm0, QWORD PTR .LC0[rip] # хули ты мне плавучего питуха в xmm0 возвращаешь?
            ret
    .L5:
            mov     rax, rdi
            and     edi, 1
            pxor    xmm0, xmm0
            shr     rax
            or      rax, rdi
            cvtsi2sd        xmm0, rax
            addsd   xmm0, xmm0
            mulsd   xmm0, QWORD PTR .LC0[rip]
            ret
    test2(unsigned long):
            sub     rsp, 8
            call    auto a<unsigned long>(unsigned long)
            movsd   xmm1, QWORD PTR .LC1[rip]
            comisd  xmm0, xmm1
            jnb     .L8
            cvttsd2si       rax, xmm0 # ну нахуй тут надо double в uint64_t конвертить
            add     rsp, 8 # почему это не делается в auto a<unsigned long>(unsigned long)
            ret
    .L8:
            subsd   xmm0, xmm1
            add     rsp, 8
            cvttsd2si       rax, xmm0
            btc     rax, 63
            ret
    .LC0:
            .long   0
            .long   1073217536
    .LC1:
            .long   0
            .long   1138753536
    
    */

    концепты-хуепты

    Запостил: j123123, 23 Марта 2019

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

    • Хуйня какая-то скомпилировалась.
      Ответить
      • Нормально. Мы просто пока не изучили все подводные камни крестов, поэтому для нас это кажется хуйнёй. Если бы мы были крестовиками с двадцатилетним стажем, для нас такое поведение крестов было бы нормой.
        Ответить
    • А всё потому, что в крестах изначально отсутствовала перегрузка функций по типу возвращаемого значения. Первое найденное применение ожидает double, поэтому кресты для всех остальных применений тоже будут возвращать double.

      Тут по идее нужно конструировать крестошаблоны.
      Ответить
      • Да всё проще... 1.5 - дабл. Умножение любой хуйни на дабл - дабл. Поэтому "a" всегда возвращает дабл.
        Ответить
        • Почему тогда оно называется "auto a<unsigned long>(unsigned long)" ?
          Или это говно относится только к принимаемым аргументам? Почему оно не подстраивает это auto по то, куда присваивается результат вызова функции?
          Ответить
          • По типам аргументов.
            Ответить
            • Кажется, теперь я понял:
              1) auto b подстраивается под тип принимаемого аргумента. Если b типа int, то создаётся auto a(int b); если b типа double, то создаётся auto a(double b).

              2) b*1.5 подстраивается под тип выражения. Произведение произвольного числа на double (а 1.5 по умолчанию double) скорее всего будет double. Если нужен целый результат, то нужно писать b*3/2 или вызывать функцию округления.

              Теперь всё логично.

              Кстати, b*3/2 может быть целым? В Паскале, в Бейсике и в Питоне для целочисленного деления отдельный оператор (соответственно div, \ и //), а в сишке нет.

              И ещё в каких-нибудь случаях результат может быть float или long double?
              Ответить
            • кстати вот интересно, в стандарте C, C++ что-то говорится о порядке операций и приведениях типа, если скажем в одном выражении суммируются int, float, double и long long какой-нибудь?

              типа вот 984798.0f + 73087 + 1998726.0 + 20836LL будет считаться как (((984734598.0f + 73087) + 1998726.0) + 20836LL) или как (984734598.0f + 73087) + (1998726.0 + 20836LL) или может быть как-нибудь так (73087 + 20836LL) + (984734598.0f + 1998726.0) ?
              Ответить
              • Скорее всего оно:
                [ Note: Operators can be regrouped according to the usual mathematical rules only where the operators
                really are associative or commutative. For example, in the following fragment
                int a, b;
                /* ... */
                a = a + 32760 + b + 5;
                the expression statement behaves exactly the same as
                a = (((a + 32760) + b) + 5);
                due to the associativity and precedence of these operators. Thus, the result of the sum (a + 32760) is next
                added to b, and that result is then added to 5 which results in the value assigned to a. On a machine in which
                overflows produce an exception and in which the range of values representable by an int is [-32768, +32767],
                the implementation cannot rewrite this expression as
                a = ((a + b) + 32765);
                since if the values for a and b were, respectively, -32754 and -15, the sum a + b would produce an exception
                while the original expression would not; nor can the expression be rewritten either as
                a = ((a + 32765) + b);
                or
                a = (a + (b + 32765));
                since the values for a and b might have been, respectively, 4 and -8 or -17 and 12. However on a machine in
                which overflows do not produce an exception and in which the results of overflows are reversible, the above
                expression statement can be rewritten by the implementation in any of the above ways because the same
                result will occur. —end note ]

                N4659, §4.6, 8

                То есть выражение будет считать так, чтобы результат был полностью эквивалентен «(((984734598.0f + 73087) + 1998726.0) + 20836LL)».
                Ответить
          • > относится только к принимаемым аргументам
            Именно.

            > куда присваивается результат
            Потому что крестоблядская типизация никогда так не умела. auto на возвращаемом типе тупо берёт тип от выражения, которое ты написал в return.
            Ответить
            • Действительно, в выражении kooryatneek = petooh + koorochka + tseeplyonok; кококомпилятору пофигу, какой тип имеет kooryatneek. Он сначала считает правую часть в том типе, в котором ему удобно, выбирая такой тип, который может без труда вместить и petooh, и koorochka, и tseeplyonok, а уже после вычисления принимает решение, сможет ли скастовать значение суммы в тип переменной kooryatneek.
              Ответить
              • > без труда вместить и petooh, и koorochka, и tseeplyonok
                Но не всегда вмещает их сумму...
                Ответить
                • Именно поэтому изобретено более 9000 способов вычисления среднего арифметического без переполнения.

                  Тупо (petooh + koorochka + tseeplyonok)/3 может вызвать переполнение и результат окажется по модулю кококококого-нибудь числа.
                  Ответить
            • А в языке Ада есть перегрузка по типу возвращаемого значения:
              function Value (Str : String) return Integer;
              function Value (Str : String) return Float;
              V : Integer := Value ("8");

              Так что язык Ада умеет «выводить» и наоборот, но в нём, в отличие от крестов, нельзя смешивать разные типы.
              Ответить
        • Вообще, умножать на полтора можно так
          uint64_t mul1_5(uint64_t a)
          {
            return a + (a >> 1);
          }

          Но это слишком сложная и неочевидная оптимизация, да и к тому же плавучий питух может иначе посчитать
          Ответить
          • Кстати, попробуй auto mul1_5(auto a) { return a + (a >> 1); }

            З.Ы. А, блин, дабл нельзя двигать :(
            Ответить
    • auto mul(auto x, auto y) {
          return x * y;
      }
      То есть шаблоны для обобщённых алгоритмов не нужны? Вот бы ещё неявный auto, как в старых сях неявный int.
      Ответить
    • https://cppinsights.io/lnk?code=I2luY2x1ZGUgPGNpbnR0eXBlcz4KCnR lbXBsYXRlIDx0eXBlbmFtZSBUPgphdXRvIGEoVCB iKSB7CiAgcmV0dXJuIGIgKiAxLjU7Cn0KCmRvdWJ sZSB0ZXN0MShkb3VibGUgaW4pCnsKICByZXR1cm4 gYShpbik7Cn0KCnVpbnQ2NF90IHRlc3QyKHVpbnQ 2NF90IGluKQp7CiAgcmV0dXJuIGEoaW4pOwp9&st d=cpp17&rev=1.0

      #include <cinttypes>
      
      template <typename T>
      auto a(T b) {
        return b * 1.5;
      }
      
      template<>
      double a<double>(double b)
      {
        return b * 1.5;
      }
      
      template<>
      double a<unsigned long>(unsigned long b)
      {
        return static_cast<double>(b) * 1.5;
      }
      
      double test1(double in)
      {
        return a(in);
      }
      
      
      uint64_t test2(uint64_t in)
      {
        return static_cast<unsigned long>(a(in));
      }
      Ответить

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