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

    +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
    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
    #include <inttypes.h>
    #include <stdio.h>
     
    typedef union
    {
      struct
      {
        #define BITG(n) uint8_t bit##n : 1
        BITG(0);
        BITG(1);
        BITG(2);
        BITG(3);
        BITG(4);
        BITG(5);
        BITG(6);
        BITG(7);
        #undef BITG
      } bits;
      uint8_t value;
    }getbit;
     
    uint8_t bit_sum(uint8_t, uint8_t);
     
     
    uint8_t bit_sum(uint8_t a, uint8_t b)
    {
      getbit op1, op2, opr;
      uint8_t carry;
      op1.value=a; op2.value=b;
      #define OP1(n) op1.bits.bit##n
      #define OP2(n) op2.bits.bit##n
      #define OPR(n) opr.bits.bit##n
      #define XOR(a,b) ((a)^(b))
      #define AND(a,b) ((a)&(b))
      OPR(0) = XOR(OP1(0), OP2(0));
      carry = AND(OP1(0), OP2(0));
      #define SETBIT(n)                \
      OPR(n) = XOR                     \
               (                       \
                 carry,                \
                 XOR(OP1(n), OP2(n))   \
               );
     
      #define CARRYBIT(n)              \
      carry = XOR                      \
              (                        \
                AND(OP1(n), OP2(n)),   \
                AND                    \
                (                      \
                  XOR(OP1(n), OP2(n)), \
                  carry                \
                )                      \
              );
      SETBIT(1);
      CARRYBIT(1);
      SETBIT(2);
      CARRYBIT(2);
      SETBIT(3);
      CARRYBIT(3);
      SETBIT(4);
      CARRYBIT(4);
      SETBIT(5);
      CARRYBIT(5);
      SETBIT(6);
      CARRYBIT(6);
      SETBIT(7);
      return opr.value;
      #undef SETBIT
      #undef CARRYBIT
      #undef OP1
      #undef OP2
      #undef OPR
      #undef XOR
      #undef AND
    }
     
    int main (int argc, char *argv[], char *envp[])
    {
      uint8_t a, b, c;
      scanf ("%"SCNu8"%"SCNu8, &a, &b);
      c = bit_sum(a,b);
      printf("%"PRIu8"\n", c);
      return 0;
    }

    Побитовое сложение двух 8-битных чисел по схеме двоичного сумматора

    Запостил: j123123, 20 Апреля 2015

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

    • Странно что никто так и не откомментил это безумие


      //Упростил
      uint8_t add(uint8_t a,uint8_t b){
         return 0==a ? b : add((a&b)<<1,a^b);
      }
      Ответить
      • Надо подумать, можно ли тут заюзать схему ускоренного переноса.
        Ответить
    • Кстати, конпелятор догадывается оптимизнуть это в сложение?
      Ответить
      • https://godbolt.org/g/hxYkcN

        Нет. К тому же многие «очевидные» для человека случаи извратов компилятор может не оптимизировать, поскольку не факт что соблюдаются corner-case, переполнения там всякие.
        Ответить
    • А может быть студент сумматоры изучал? Цифровой логический уровень, или как там оно называется.
      Ответить
      • Но это лучше делать на каком-нибудь verilog'е, имхо. Там это выглядело бы немного естественней:
        module add(input [7:0] a, input [7:0] b, output [7:0] sum);
            wire tmp[7:0], carry[8:0];
            assign carry[0] = 0;
            for (i = 0; i < 8; i = i + 1) begin
                assign tmp[i] = a[i] ^ b[i];
                assign out[i] = tmp[i] ^ carry[i];
                assign carry[i+1] = (a[i] && b[i]) || (tmp[i] && carry[i]);
            end;
        endmodule
        Ответить
        • Естественней взять схему с готовым сумматором, а не писать его руками в 2018

          Я не уверен, кстати, что вот прямо всех студентов учат verilogу.
          Ответить
          • Ну да, можно просто out = a + b, синтезатор сам справится.
            Ответить
            • А ты реально пишешь на verilogе на работе? И потом по этому fpga или asic собирают?
              Ответить
              • Не, просто по фану под циклоняшку.
                Ответить
              • Было бы интересно поработать над asic'ами. Но, боюсь, без опыта на такое не берут — слишком большая цена фейла. А вот на FPGA можно попробовать.
                Ответить

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