3-bit unsigned integer in c

I am creating a deep neural network for the game connect-4, which should compete with other AI bots on a very limited machine (I don’t know the specific limitations yet, only I will have only a few cores and a small amount of memory). Thus, I try to optimize my training set in any way. He currently presents states on boards as such:

b for space (without fragment)

x for the presence of "x"

o for the "o" of the present fragment

win for won settings

loss for lost installation

draw for hand-drawn installation

Essentially, I'm trying to match it so that my 3-bit integer can replace these heavy strings. I was thinking about using short, but it turned out to be worse than char16 bits. I want to display it like this:

000b

001x

010o

011win

100loss

101draw

Since I can represent these states in 3 bits of space instead of characters (8 bits per char, yikes!), I would like to try to do this. However, I'm not sure how to instantiate a variable like this in c.

The training set is 67557 lines long, representing a 6x7 board in each line with a win / loss / draw sentence. Thus, saving 5 bits per char will save the bits (5*6*7)+(5*1) = 215in each line and the 215*67557 = 14524755bit as a whole (1.81 MB in total 2.90 MB, reducing the total space by 62%).

+4
3

, .

  • ( )
  • + ? W/L/D

. . , , "" .

:

. , AI , . , , : .

, , . , /// . , , .

  • bit-board: (, ), 64- unsigned int , , , . , , .

    ( o, x) . connect-4 6 * 7 , 64 , 32b . popcount(board.o) , os . assert(o & x == 0) , o x .

    42b , /. 48- ( ) /. , . .

    - board[0][0] && board[0][1] && board[0][2] && board[0][3] ( ) -. , , , , , . || &&, . o x o|x . , .

    , , , . , , , , , 2--.

    , 64 , 8x8, 7x6. , 64- . , , , , - , , , . . 8 ( ). , 42- . x86, 4 , 8- (AX (low16 RAX) AL AH), ( , , , ) 7 4 - bsr (--) .

// Sample bitboard implementation:
struct game_state {
    struct board_state {
       uint64_t o, x;
    } board;
    enum winlose { GAME_UNDECIDED=0, GAME_WIN_O, GAME_WIN_X, GAME_DRAW } victory;
};
  • : . . board[row][col] C, 42 * 2 . , . 64 . ( , o|x. , , . , / , /. .

  • : . board[i][j] && board[i][j+1] - , , , - . , x86 , . .

    x, o, , x, o. , . , x o .

// Sample byte-array implementation:
enum boardpos {
    POS_EMPTY = 0,
    POS_O = 1<<0,
    POS_X = 1<<1,
    POS_OCCUPIED = 1<<3
};
// maybe #define for these constants instead?

struct game_state {
    struct board_state {
       uint8_t pos[6][7];
    } board;
    enum winlose { GAME_UNDECIDED=0, GAME_WIN_O, GAME_WIN_X, GAME_DRAW } victory;
    // or maybe stuff the winlose info into the high bits of board.pos[0][0]?
    // Not much point, since the struct will probably be the same size after padding anyway.
};

:

, xbbb...ooxbbw. , 43 ( 43, ). - , , , , . 'n'.

, . . , xb2o1xb1w. , . , , x x, capital x xes. , . LZOP LZ4 , , .

:

, . , . 2 , , , , x o . , . 4531,985,219,092 , 0 42 . 2 ^ 42. , 43 , , . IDK, 43- , , (.. , , .)

, , o x w/d/d 12 16 , .

// do some pre-processor stuff to choose between GNU C __attribute__ ((__packed__))
// and the MSVC #pragma pack
struct __attribute__ ((__packed__)) compact_game_state {
    struct __attribute__ ((__packed__)) compact_board_state {
       uint64_t o:42, x:42;
    } board; // sizeof = 11
    uint8_t victory;
}; // sizeof = 12

struct semi_compact_game_state {
    struct __attribute__ ((__packed__)) semi_compact_board_state {
       uint64_t o:48, x:48;
    } board; // 96 bits = 12 bytes
    enum winlose victory; // another 4 bytes
};

g++: . godbolt.

- endian-agnostic code, , . , , , . -endian, , , / . - , , .

, 2- . , , , , . 2 , { POS_EMPTY, POS_O|POS_OCCUPIED, POS_X|POS_OCCUPIED }. - , . 84 , 32 64- . 128- . // 2- .

12- uint32_t uint64_t uint32_t - . uint8_t, . 11 , - . 1/12- , . , , x86, . (64- 64b , 12B-, , , , -, . )

, . , .

, , .

, , . 2- (, . ).

, . ( .)

+2

?

struct S {
    unsigned w : 3;
    unsigned x : 3;
    unsigned y : 3;
    unsigned z : 3;
};

sizeof(struct S) == 2, 4 !

- ...

struct S myS;
s.w = 0; // Okay
s.x = 6; // Okay
s.y = 8; // Will overflow/wrap-around (why do the standards differentiate between those two?)

, - ...

struct S first;
struct S second;

, , , , () 32 , , , , , 24 .

, , , (, 8-, : 8 * 3 == 24; 24 % 8 == 0), , , . , , 4 S.

BTW. &s.x sizeof(s.x), .

+7

If the machine is limited, and you have to compete (in time), then you DO NOT want to go into heavy operations with the processor on integer integer bit targets. It is best to use machine word size. It is best to use byte dimensional numbers, as many machines have efficient byte size operations.

It is always a matter of optimizing speed or memory usage.

+2
source

Source: https://habr.com/ru/post/1609761/


All Articles