=======================================
Signed/Unsigned Integer Arithmetic in C
=======================================
Vineel Kovvuri - http://vineelkovvuri.com

Contents
========

    1 - Introduction
    2 - How signedness is represented in the hardware?
    3 - How signedness is interpreted in assembly?
    4 - Signed vs Unsigned integers in C
    5 - Integer Arithmetic Conversions in C
    5.1 - Rank
    5.2 - Integer Promotions
    5.3 - Usual arithmetic conversions
    5.3.1 - Rule 2c interpretation
    5.3.2 - Rule 2d interpretation
    5.3.3 - Rule 2e interpretation
    5.4 - Integer conversion matrix on LLP64 Programming Model
    6 - References
    7 - Binary representation
    7.1 - unsigned numbers
    7.2 - signed numbers

1. Introduction
===============

    This article is about understanding how integer conversions happen in C
    language. C standard defines the integer conversion rules not specific to any
    architecture. It makes things more complicated for the programmers to try and
    understand them.

    Why do we need integer conversions at all? The answer is simple we need to have
    single type for the expression. Let's say we have an expression
    <expr1><op><expr2>when expr1 and expr2 are different types, we want the
    resulting expression from this to have one type.

    The C99 specification defines below set of integer types called 'standard
    integer types'. Interestingly, the sizes of these integer types are not defined
    at all. It only defines the minimum supported size. For example, int need not be
    8 bytes long on x64 platforms, the only definition for int is it should have at
    least 16 bits and similarly long should have at least 32 bits it need not be
    8 bytes long. Depending on the platform and the processor architecture the ABI
    (Application Binary Interface) and the 64bit programming model will define the
    size of these basic types. Windows x64 follows LLP64(meaning only 'long long'
    and pointer size is 64 bit wide), So below are the sizes of the standard types
    that we are sticking to in this article.

            =================== ========
            Type                 Size
            =================== ========
            signed char          1 bytes
            unsigned char        1 bytes
            signed short         2 bytes
            unsigned short       2 bytes
            signed int           4 bytes
            unsigned int         4 bytes
            signed long          4 bytes
            unsigned long        4 bytes
            signed long long     8 bytes
            unsigned long long   8 bytes
            =================== ========

    Also, The specification leaves other aspects of C language definition undefined
    and this made room for optimization for the compilers. For example, the result
    of signed arithmetic leading to overflow/underflow is not defined because the
    specification predates to the machine architectures when 2's complement
    representation for -ve numbers is not universal, Even though virtually every
    architecture now uses 2's complement representation for -ve numbers. Hence the
    result of unsigned overflow/underflow is well defined but not signed
    overflow/underflow!

2. How signed-ness is represented in the hardware?
==================================================

    Processors do have the concept of signed/unsigned, but unlike in C language,
    where this information is baked into the variable type definition, processor
    registers do not hold the type/signed/unsigned information. After all, registers
    are just placeholders of data. But the instructions themselves do have the
    notion of signed/unsigned, That is why we have signed 'imul', unsigned 'mul',
    signed (JL/JG) vs unsigned(JB/JA) jump instructions. This is an important
    distinction between programming languages and machine code. It helps in
    understanding how high-level code gets translated to underlying machine code.
    Instructions which produce/consume signed data understand that -ve numbers
    should be in 2's complement form. So if a register (8bit) has 11110110 it's up
    to the instruction to treat that data as either -10 (signed) or 246 (unsigned).
    If an operation results in a -ve result say -5 then destination register will be
    written 11111011(2's complement representation of -5). 'add' and 'sub'
    instructions themselves are not affected by signed and unsigned numbers because
    of modulo arithmetic.

3. How signed-ness is interpreted in assembly?
==============================================

    In one of the above paragraphs, we said, processor registers does not hold any
    signed/unsigned type information with them and it's up to the instructions to
    interpret the data as either signed or unsigned. But the interesting thing about
    x86/x64 processors is, they provide a flag register(EFLAGS) where some of the
    bits are called Status Flags. These bits represent the status of what happened
    with the previous instruction.

    The most important flags of these for our discussion are
        1.  Carry flag - Set if an arithmetic operation generates a carry or a
            borrow out of the most significant bit of the result; cleared otherwise.
            This flag indicates an overflow condition for unsigned-integer
            arithmetic.
        2.  Sign flag - Set equal to the most significant bit of the result, which
            is the sign bit of a signed integer. (0 indicates a positive value and 1
            indicates a negative value.)
        3.  Overflow flag - Set if the integer result is too large a positive number
            or too small a negative number (excluding the sign-bit) to fit in the
            destination operand cleared otherwise. This flag indicates an overflow
            condition for signed-integer (two's complement) arithmetic

    Of the above three status flags, Carry flag is obvious but other two flags need
    some explanation. Sign flag is set irrespective of whether you are treating the
    numbers as positive or negative, All it cares is if the result's MSB is set or
    not.

    For example in below code, 'sub' can treat 0x81 as -127 or +129. So the result
    can also be either interpreted as -128 or +128, But the processor after
    executing 'sub' indicates this possibility in Sign Flag. So operations(JA/JB)
    who want to treat the result an unsigned will ignore this sign flag whereas
    operations (like JG/JL) who treat it as signed will take this sign flag into
    account.

        mov al, 0x81
        sub al, 0x1 // This triggers sign flag

    Overflow flag is a little different. First of all, the Overflow flag is not set
    when an operation results in an overflow of the number that can be represented
    in a register. Like for example, if we try to add 1 to 0xff does not set this
    bit.

        mov al, 0xFF // 0b11111111
        add al, 0x1  // This will not trigger Overflow flag

    Overflow flag is mainly meant for indicating if there is a chance of result if
    interpreted as signed will cross beyond what can be represented in the register.
    for example if we take a byte(al) it can contain value from 0b00000000(0) to
    0b11111111(255) as unsigned or 0b10000000(-128) to 0b01111111(127) as signed
    number. Now overflow flag is set when a result goes beyond 0b01111111 i.e., too
    large a positive number and less than 0b10000000 i.e., too small a negative
    number

        mov al, 0x7e // This is always positive
        add al, 0x2  // This will trigger overflow flag

    Let us see how overflow flag is used to determine the below conditional when
    var1 and var2 are signed numbers.

        if (var1 < var2) {
            printf("var1 < var2");
        }

    The above code is translated to cmp followed by jl. cmp does var1-var2. And jl
    says execute printf if SF != OF. Now lets see the combinations why SF needs to
    be not equal to OF

        var1 = -125;
        var2 = 10;
        var1 - var2 => -135 => which cannot be represented in a byte meaning the
                               sign bit of the byte will not be set but the overflow
                               bit gets set. So SF=0 and
        OF=1
        var1 = -120;
        var2 = -100;
        var1 - var2 => -20 => this can be represented in a byte and its -ve so SF = 1
                              but because it is still under the range of singed
                              numbers representable in a byte OF = 0

    That is why jl is defined as SF != OF, When this is true it means var1 < var2
    even if var1 and var2 are signed(meaning -ve numbers)

4. Signed vs Unsigned integers in C
===================================

    Signed numbers are the way -ve numbers are represented and unsigned numbers are
    the way in which +ve numbers are represented. If let's say a data type has 1
    byte of storage then the possible bit representation will be from 0b00000000
    (0) - 0b11111111(255). Now, these 255 valid slots can be interpreted as all
    positive numbers or divide the range into two halves and call one half of the
    slot as positive and other as negative numbers. There are other alternate
    representations for -ve number but almost all systems use 2's complement
    notation to represent -ve numbers. The take away here is if we include -ve
    number in the 255 slots then we will represent from -128 to 127. According to
    2's complement notation -128 is represented as 0b10000000(0x80) whereas 127 is
    represented as 0b01111111 (0x7F).

5. Integer Arithmetic Conversions in C
======================================

    C language defines below set of rules to convert the arguments in an expression.

5.1 Rank
========

    Every integer type has an integer conversion rank defined as follows:
        1.  No two signed integer types shall have the same rank, even if they have
            the same representation.
        2.  The rank of a signed integer type shall be greater than the rank of any
            signed integer type with less precision.
        3.  The rank of long long int shall be greater than the rank of long int,
            which shall be greater than the rank of int, which shall be greater than
            the rank of short int, which shall be greater than the rank of signed char.
        4.  The rank of any unsigned integer type shall equal the rank of the
            corresponding signed integer type, if any.
        5.  The rank of any standard integer type shall be greater than the rank of
            any extended integer type with the same width.
        6.  The rank of char shall equal the rank of signed char and unsigned char.
        7.  The rank of Bool shall be less than the rank of all other standard
            integer types.
        8.  The rank of any enumerated type shall equal the rank of the compatible
            integer type (see 6.7.2.2).
        9.  The rank of any extended signed integer type relative to another
            extended signed integer type with the same precision is
            implementation-defined, but still subject to the other rules for
            determining the integer conversion rank.
        10. For all integer types T1, T2, and T3, if T1 has greater rank than T2 and
            T2 has greater rank than T3, then T1 has greater rank than T3. At a high
            level the gist of above rules is as follows

        Rank(signed char) == Rank(unsigned char) < Rank(signed short) == Rank(unsigned
        short) < Rank(signed int) == Rank(unsigned int) < Rank(signed long) ==
        Rank(unsigned long) < Rank(signed long long) == Rank(unsigned long long)

5.2 Integer Promotions
======================

    The following may be used in an expression wherever an int or unsigned int may be
    used:

        *   An object or expression with an integer type whose integer conversion rank
            is less than or equal to the rank of int and unsigned int.
        *   A bit-field of type Bool, int, signed int, or unsigned int.
        *   1a) If an int can represent all values of the original type, the value is
            converted to an int;
        *   1b) otherwise, it is converted to an unsigned int. These are called the
            integer promotions. All other types are unchanged by the integer
            promotions.

5.3 Usual arithmetic conversions
================================

    *   2a) If both operands have the same type, then no further conversion is
        needed.
    *   2b) Otherwise, if both operands have signed integer types or both have
        unsigned integer types, the operand with the type of lesser integer
        conversion rank is converted to the type of the operand with greater
        rank.
    *   2c) Otherwise, if the operand that has unsigned integer type has rank
        greater or equal to the rank of the type of the other operand, then the
        operand with signed integer type is converted to the type of the operand
        with unsigned integer type.
    *   2d) Otherwise, if the type of the operand with signed integer type can
        represent all of the values of the type of the operand with unsigned
        integer type, then the operand with unsigned integer type is converted
        to the type of the operand with a signed integer type.
    *   2e) Otherwise, both operands are converted to the unsigned integer type
        corresponding to the type of the operand with signed integer type.

5.3.1 Rule 2c interpretation
============================

    The gist of 2c is to make sense of expressions like z = a+b where a is singed
    number and b is unsigned number. Now a 4 byte signed int is added to 8 byte
    unsigned long long, according to this rule 4 byte signed int will become 8 byte
    unsigned long long. The important point to remember here is conversion of signed
    int to unsigned long long, The way the compiler does this is by sign extend 4
    byte signed number so that its absolute value will not change i.e.., -10 remain
    -10 whether it is a 4 byte or 8 byte. But according to these rules the
    expression will have the type unsigned long long so statements like below will
    result in unexpected behavior. Since the var1+var2 is an unsigned expression the
    compiler will enforce it by using a unsigned jump instruction called jae instead
    of jge instruction.

                        .----------------This bit will sign extend to all 1's
                        11111011            signed short a = -5
                1111111111111011            unsigned int a = -5
              + 0000000000001010            unsigned int b = 10
              = 0000000000000101            unsigned int
        Figure 1: signed number converted to unsigned numbers

    Whenever a signed data type has to be converted to unsigned data type the
    absolute value remains unchanged because of sign extension will be done using
    movsx instruction. So if a variable is type signed short with value -10, when
    this variable is sign extended to unsigned int the value of even after the
    conversion remains -10 when interpreted as singed int because the binary
    represent for -10 for 2 byte storage and 4 byte storage yields the same.

    godbolt's compiler explorer is very helpful in understanding how the compiler
    translates expressions and apply the above rules. Clang AST view especially
    helps in graphically looking at how these promotions/conversion happen

        signed int var1 = -100;
        unsigned long long var2 = 10;
        if (var1 + var2 < 0) {
            //resulting unsigned long long expression will never be lessthan 0
            printf("This will never get printed");
        }

        $LN4:
            sub rsp, 56 ; 00000038H
            mov DWORD PTR var1$[rsp], -100          ; ffffffffffffff9cH
            mov QWORD PTR var2$[rsp], 10
            movsxd rax, DWORD PTR var1$[rsp]
            add rax, QWORD PTR var2$[rsp]
            test rax, rax
            jae SHORT $LN2@main                     //This is an unsigned jump
            lea rcx, OFFSET FLAT:$SG4416
            call printf
        $LN2@main:
            xor eax, eax
            add rsp, 56 ; 00000038H
            ret 0
        main ENDP

        Fragment of clang's AST for above program
        |-BinaryOperator <line:7:9, col:23> 'bool' '<'
        | |-BinaryOperator <col:9, col:16> 'unsigned long long' '+'
        | | |-ImplicitCastExpr <col:9> 'unsigned long long' <IntegralCast>
        | | | `-ImplicitCastExpr <col:9> 'int' <LValueToRValue>
        | | | `-DeclRefExpr <col:9> 'int' lvalue Var 0x55ea65e030e0 'var1' 'int'
        | | `-ImplicitCastExpr <col:16> 'unsigned long long' <LValueToRValue>
        | | `-DeclRefExpr <col:16> 'unsigned long long' lvalue Var 0x55ea65e031b0,
              'var2' 'unsigned long long'
        | `-ImplicitCastExpr <col:23> 'unsigned long long' <IntegralCast>
        | `-IntegerLiteral <col:23> 'int' 0

    These rules can only dictate what need to be done for each expression in a
    statement one at a time. It cannot determine the type of the complete statement
    at once because of this we might end up with unexpected results if we are not
    careful enough about how the type is propagating. for example,in var = exp1 +
    exp2*exp3 the rules can only tell how exp2*exp3 interact and how that result
    interacts with exp1. exp2*exp3's new type may not gel well with exp1 and might
    result in an unexpected result.

5.3.2 Rule 2d interpretation
============================

    Rule 2d tries to make sense when you have two variables with small the unsigned
    number and signed number are present in an expression and the singed storage can
    hold the unsigned number entirely, then by this rule, the unsigned number gets
    converted to signed number.

                        .----------------The value is not sign extended in case of
                        |                unsigned numbers because 1 here does not
                        |                mean anything special except some large +ve
                        V                value
                        00000101            unsigned short a = 5
                0000000011111011            signed int a = 5
              + 1111111111110110            signed int b = -10
              = 1111111111111011            signed int

        Figure 2: unsigned number converted to signed numbers

    For example:
        unsigned int var1 = 100;
        signed long long var2 = -10;
        if (var1 + var2 < 0) { //resulting in signed long long expression
            printf("This gets printed if var1 + var2 is < 0");
        }

            sub rsp, 56 ; 00000038H
            mov DWORD PTR var1$[rsp], 100 ; 00000064H
            mov QWORD PTR var2$[rsp], -10
            mov eax, DWORD PTR var1$[rsp]
            add rax, QWORD PTR var2$[rsp]
            test rax, rax
            jge SHORT $LN2@main // This is a signed jump
            lea rcx, OFFSET FLAT:$SG4869
            call printf
        $LN2@main:
            xor eax, eax
            add rsp, 56 ; 00000038H
            ret 0
        main ENDP

        Fragment of clang's AST for above program
        |-BinaryOperator <line:7:9, col:23> 'bool' '<'
        | |-BinaryOperator <col:9, col:16> 'long long' '+'
        | | |-ImplicitCastExpr <col:9> 'long long' <IntegralCast>
        | | | `-ImplicitCastExpr <col:9> 'unsigned int' <LValueToRValue>
        | | | `-DeclRefExpr <col:9> 'unsigned int' lvalue Var 0x56305e1200e0
                , 'var1' 'unsigned int'
        | | `-ImplicitCastExpr <col:16> 'long long' <LValueToRValue>
        | | `-DeclRefExpr <col:16> 'long long' lvalue Var 0x56305e1201a8 'var2'
                , 'long long'
        | `-ImplicitCastExpr <col:23> 'long long' <IntegralCast>
        | `-IntegerLiteral <col:23> 'int' 0

5.3.3 Rule 2e interpretation
============================

    And finally, Rule 2e is applied only between unsigned int and signed long
    because neither 2c,2d fits these type on LLP64 model. One interesting thing we
    can observe if read between the lines is, the resultant type has unsignedness
    but the type is of signed variable and also both operand types are converted
    unlike other rules. For example:

        unsigned int var1 = 100; // this gets converted to unsigned long
        signed long var2 = -10;  // this will also converted to unsigned long
        if (var1 + var2 < 0) {   // resulting type is unsigned long
            printf("This will not be printed");
        }

            sub rsp, 56 ; 00000038H
            mov DWORD PTR var1$[rsp], 100 ; 00000064H
            mov DWORD PTR var2$[rsp], -10
            mov eax, DWORD PTR var2$[rsp]
            mov ecx, DWORD PTR var1$[rsp]
            add ecx, eax
            mov eax, ecx
            test eax, eax
            jae SHORT $LN2@main // This is an unsigned jump
            lea rcx, OFFSET FLAT:$SG4869
            call printf
        $LN2@main:
            xor eax, eax
            add rsp, 56 ; 00000038H
            ret 0
        main ENDP

        Fragment of clang's AST for above program
        |-BinaryOperator <line:7:9, col:23> 'bool' '<'
        | |-BinaryOperator <col:9, col:16> 'long' '+'
        | | |-ImplicitCastExpr <col:9> 'long' <IntegralCast>
        | | | `-ImplicitCastExpr <col:9> 'unsigned int' <LValueToRValue>
        | | | `-DeclRefExpr <col:9> 'unsigned int' lvalue Var 0x564cedbd0100
                ,'var1' 'unsigned int'
        | | `-ImplicitCastExpr <col:16> 'long' <LValueToRValue>
        | | `-DeclRefExpr <col:16> 'long' lvalue Var 0x564cedbd01c8 'var2' 'long'
        | `-ImplicitCastExpr <col:23> 'long' <IntegralCast>
        | `-IntegerLiteral <col:23> 'int' 0

5.4 Integer conversion matrix on LLP64 Programming Model
========================================================

    Below table summaries the rules applied for each expression combination

    +------------------------+---------------------+------------------------------------------------------------------------------------+
    |                        |    Size(MSVC x64)   |  1       1        2       2        4       4        4      4        8      8       |
    |LLP64 Programming Model +---------------------+------------------------------------------------------------------------------------+
    |                        |    Rank             |  1       1        2       2        3       3        4      4        5      5       |
    +---------------+--------+---------------------+------------------------------------------------------------------------------------+
    |Size(MS VC x64)|Rank    |<type1> oper <type2> |  signed  unsigned signed  unsigned signed  unsigned signed unsigned signed unsigned|
    |               |        |                     |  char    char     short   short    int     int      long   long     long   long    |
    |               |        |                     |                                                                     long   long    |
    +---------------+--------+---------------------+------------------------------------------------------------------------------------+
    | 1             | 1      |signed char          |  1a      1a       1a      1a       1a      1b       2b     2c       2b     2c      |
    | 1             | 1      |unsigned char        |          1a       1a      1a       1a      1b       2d     2b       2d     2b      |
    | 2             | 2      |signed short         |                   1a      1a       1a      1b       2b     2c       2b     2c      |
    | 2             | 2      |unsigned short       |                           1a       1a      1b       2d     2b       2d     2b      |
    | 4             | 3      |signed int           |                                    2a      1b       2b     2c       2b     2c      |
    | 4             | 3      |unsigned int         |                                            2a       2e     2b       2d     2b      |
    | 4             | 4      |signed long          |                                                     2a     2c       2b     2c      |
    | 4             | 4      |unsigned long        |                                                            2a       2d     2b      |
    | 8             | 5      |signed long long     |                                                                     2a     2c      |
    | 8             | 5      |unsigned long long   |                                                                            2a      |
    +---------------+--------+---------------------+------------------------------------------------------------------------------------+
    Figure 3: Rules applied for each combination of expression

    Below table summaries the resulting data type of the expression

    +------------------------+---------------------+--------------------------------------------------------------------------------------+
    |                        |    Size(MSVC x64)   |  1       1        2       2        4       4        4        4        8      8       |
    |LLP64 Programming Model +---------------------+--------------------------------------------------------------------------------------+
    |                        |    Rank             |  1       1        2       2        3       3        4        4        5      5       |
    +---------------+--------+---------------------+--------------------------------------------------------------------------------------+
    |Size(MS VC x64)|Rank    |<type1> oper <type2> |  signed  unsigned signed  unsigned signed  unsigned signed   unsigned signed unsigned|
    |               |        |                     |  char    char     short   short    int     int      long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    +---------------+--------+---------------------+--------------------------------------------------------------------------------------+
    | 1             | 1      |signed char          |  signed  signed   signed  signed   signed  unsigned signed   unsigned signed unsigned|
    |               |        |                     |  int     int      int     int      int     int      long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 1             | 1      |unsigned char        |          signed   signed  signed   signed  unsigned unsigned unsigned signed unsigned|
    |               |        |                     |          int      int     int      int     int      long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 2             | 2      |signed short         |                   signed  signed   signed  unsigned signed   unsigned signed unsigned|
    |               |        |                     |                   int     int      int     int      long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 2             | 2      |unsigned short       |                           signed   signed  unsigned signed   unsigned signed unsigned|
    |               |        |                     |                           int      int     int      long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 4             | 3      |signed int           |                                    signed  unsigned signed   unsigned signed unsigned|
    |               |        |                     |                                    int     int      long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 4             | 3      |unsigned int         |                                            unsigned unsigned unsigned signed unsigned|
    |               |        |                     |                                            int      long*    long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 4             | 4      |signed long          |                                                     signed   unsigned signed unsigned|
    |               |        |                     |                                                     long     long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 4             | 4      |unsigned long        |                                                              unsigned signed unsigned|
    |               |        |                     |                                                              long     long   long    |
    |               |        |                     |                                                                       long   long    |
    | 8             | 5      |signed long long     |                                                                       signed unsigned|
    |               |        |                     |                                                                       long   long    |
    |               |        |                     |                                                                       long   long    |
    | 8             | 5      |unsigned long long   |                                                                              unsigned|
    |               |        |                     |                                                                              long    |
    |               |        |                     |                                                                              long    |
    +---------------+--------+---------------------+--------------------------------------------------------------------------------------+
    Figure 4: Resulting type of the expression

6. References
=============

    1. INT02-C. Understand integer conversion rules - https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules
    2. C99 Standard - http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
    3. Should I use Signed or Unsigned Ints In C? (Part 1) - http://blog.robertelder.org/signed-or-unsigned/
    4. Should I use Signed or Unsigned Ints In C? (Part 2) - http://blog.robertelder.org/signed-or-unsigned-part-2/
    5. X86 Opcode and Instruction Reference - http://ref.x86asm.net/coder-abc.html
    6. Why is imul used for multiplying unsigned numbers? - https://stackoverflow.com/a/42589535/2407966
    7. System V Application Binary Interface AMD64 Architecture Processor Supplement - https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
    8. 64-Bit Programming Models: Why LP64? - http://www.unix.org/version2/whatsnew/lp64_wp.html
    9. Why did the Win64 team choose the LLP64 model? - https://blogs.msdn.microsoft.com/oldnewthing/20050131-00/?p=36563
    10. Abstract Data Models - https://docs.microsoft.com/en-us/windows/desktop/winprog64/abstract-data-models

7. Binary representation
========================

7.1 unsigned numbers
====================

    000|0x0 |00000000 # 064|0x40|01000000 # 128|0x80|10000000 # 192|0xc0|11000000
    001|0x1 |00000001 # 065|0x41|01000001 # 129|0x81|10000001 # 193|0xc1|11000001
    002|0x2 |00000010 # 066|0x42|01000010 # 130|0x82|10000010 # 194|0xc2|11000010
    003|0x3 |00000011 # 067|0x43|01000011 # 131|0x83|10000011 # 195|0xc3|11000011
    004|0x4 |00000100 # 068|0x44|01000100 # 132|0x84|10000100 # 196|0xc4|11000100
    005|0x5 |00000101 # 069|0x45|01000101 # 133|0x85|10000101 # 197|0xc5|11000101
    006|0x6 |00000110 # 070|0x46|01000110 # 134|0x86|10000110 # 198|0xc6|11000110
    007|0x7 |00000111 # 071|0x47|01000111 # 135|0x87|10000111 # 199|0xc7|11000111
    008|0x8 |00001000 # 072|0x48|01001000 # 136|0x88|10001000 # 200|0xc8|11001000
    009|0x9 |00001001 # 073|0x49|01001001 # 137|0x89|10001001 # 201|0xc9|11001001
    010|0xa |00001010 # 074|0x4a|01001010 # 138|0x8a|10001010 # 202|0xca|11001010
    011|0xb |00001011 # 075|0x4b|01001011 # 139|0x8b|10001011 # 203|0xcb|11001011
    012|0xc |00001100 # 076|0x4c|01001100 # 140|0x8c|10001100 # 204|0xcc|11001100
    013|0xd |00001101 # 077|0x4d|01001101 # 141|0x8d|10001101 # 205|0xcd|11001101
    014|0xe |00001110 # 078|0x4e|01001110 # 142|0x8e|10001110 # 206|0xce|11001110
    015|0xf |00001111 # 079|0x4f|01001111 # 143|0x8f|10001111 # 207|0xcf|11001111
    016|0x10|00010000 # 080|0x50|01010000 # 144|0x90|10010000 # 208|0xd0|11010000
    017|0x11|00010001 # 081|0x51|01010001 # 145|0x91|10010001 # 209|0xd1|11010001
    018|0x12|00010010 # 082|0x52|01010010 # 146|0x92|10010010 # 210|0xd2|11010010
    019|0x13|00010011 # 083|0x53|01010011 # 147|0x93|10010011 # 211|0xd3|11010011
    020|0x14|00010100 # 084|0x54|01010100 # 148|0x94|10010100 # 212|0xd4|11010100
    021|0x15|00010101 # 085|0x55|01010101 # 149|0x95|10010101 # 213|0xd5|11010101
    022|0x16|00010110 # 086|0x56|01010110 # 150|0x96|10010110 # 214|0xd6|11010110
    023|0x17|00010111 # 087|0x57|01010111 # 151|0x97|10010111 # 215|0xd7|11010111
    024|0x18|00011000 # 088|0x58|01011000 # 152|0x98|10011000 # 216|0xd8|11011000
    025|0x19|00011001 # 089|0x59|01011001 # 153|0x99|10011001 # 217|0xd9|11011001
    026|0x1a|00011010 # 090|0x5a|01011010 # 154|0x9a|10011010 # 218|0xda|11011010
    027|0x1b|00011011 # 091|0x5b|01011011 # 155|0x9b|10011011 # 219|0xdb|11011011
    028|0x1c|00011100 # 092|0x5c|01011100 # 156|0x9c|10011100 # 220|0xdc|11011100
    029|0x1d|00011101 # 093|0x5d|01011101 # 157|0x9d|10011101 # 221|0xdd|11011101
    030|0x1e|00011110 # 094|0x5e|01011110 # 158|0x9e|10011110 # 222|0xde|11011110
    031|0x1f|00011111 # 095|0x5f|01011111 # 159|0x9f|10011111 # 223|0xdf|11011111
    032|0x20|00100000 # 096|0x60|01100000 # 160|0xa0|10100000 # 224|0xe0|11100000
    033|0x21|00100001 # 097|0x61|01100001 # 161|0xa1|10100001 # 225|0xe1|11100001
    034|0x22|00100010 # 098|0x62|01100010 # 162|0xa2|10100010 # 226|0xe2|11100010
    035|0x23|00100011 # 099|0x63|01100011 # 163|0xa3|10100011 # 227|0xe3|11100011
    036|0x24|00100100 # 100|0x64|01100100 # 164|0xa4|10100100 # 228|0xe4|11100100
    037|0x25|00100101 # 101|0x65|01100101 # 165|0xa5|10100101 # 229|0xe5|11100101
    038|0x26|00100110 # 102|0x66|01100110 # 166|0xa6|10100110 # 230|0xe6|11100110
    039|0x27|00100111 # 103|0x67|01100111 # 167|0xa7|10100111 # 231|0xe7|11100111
    040|0x28|00101000 # 104|0x68|01101000 # 168|0xa8|10101000 # 232|0xe8|11101000
    041|0x29|00101001 # 105|0x69|01101001 # 169|0xa9|10101001 # 233|0xe9|11101001
    042|0x2a|00101010 # 106|0x6a|01101010 # 170|0xaa|10101010 # 234|0xea|11101010
    043|0x2b|00101011 # 107|0x6b|01101011 # 171|0xab|10101011 # 235|0xeb|11101011
    044|0x2c|00101100 # 108|0x6c|01101100 # 172|0xac|10101100 # 236|0xec|11101100
    045|0x2d|00101101 # 109|0x6d|01101101 # 173|0xad|10101101 # 237|0xed|11101101
    046|0x2e|00101110 # 110|0x6e|01101110 # 174|0xae|10101110 # 238|0xee|11101110
    047|0x2f|00101111 # 111|0x6f|01101111 # 175|0xaf|10101111 # 239|0xef|11101111
    048|0x30|00110000 # 112|0x70|01110000 # 176|0xb0|10110000 # 240|0xf0|11110000
    049|0x31|00110001 # 113|0x71|01110001 # 177|0xb1|10110001 # 241|0xf1|11110001
    050|0x32|00110010 # 114|0x72|01110010 # 178|0xb2|10110010 # 242|0xf2|11110010
    051|0x33|00110011 # 115|0x73|01110011 # 179|0xb3|10110011 # 243|0xf3|11110011
    052|0x34|00110100 # 116|0x74|01110100 # 180|0xb4|10110100 # 244|0xf4|11110100
    053|0x35|00110101 # 117|0x75|01110101 # 181|0xb5|10110101 # 245|0xf5|11110101
    054|0x36|00110110 # 118|0x76|01110110 # 182|0xb6|10110110 # 246|0xf6|11110110
    055|0x37|00110111 # 119|0x77|01110111 # 183|0xb7|10110111 # 247|0xf7|11110111
    056|0x38|00111000 # 120|0x78|01111000 # 184|0xb8|10111000 # 248|0xf8|11111000
    057|0x39|00111001 # 121|0x79|01111001 # 185|0xb9|10111001 # 249|0xf9|11111001
    058|0x3a|00111010 # 122|0x7a|01111010 # 186|0xba|10111010 # 250|0xfa|11111010
    059|0x3b|00111011 # 123|0x7b|01111011 # 187|0xbb|10111011 # 251|0xfb|11111011
    060|0x3c|00111100 # 124|0x7c|01111100 # 188|0xbc|10111100 # 252|0xfc|11111100
    061|0x3d|00111101 # 125|0x7d|01111101 # 189|0xbd|10111101 # 253|0xfd|11111101
    062|0x3e|00111110 # 126|0x7e|01111110 # 190|0xbe|10111110 # 254|0xfe|11111110
    063|0x3f|00111111 # 127|0x7f|01111111 # 191|0xbf|10111111 # 255|0xff|11111111

7.2 signed numbers
==================

    -128|0x80|10000000 # -064|0xc0|11000000 # 0000|0x0 |00000000 # 0064|0x40|01000000
    -127|0x81|10000001 # -063|0xc1|11000001 # 0001|0x1 |00000001 # 0065|0x41|01000001
    -126|0x82|10000010 # -062|0xc2|11000010 # 0002|0x2 |00000010 # 0066|0x42|01000010
    -125|0x83|10000011 # -061|0xc3|11000011 # 0003|0x3 |00000011 # 0067|0x43|01000011
    -124|0x84|10000100 # -060|0xc4|11000100 # 0004|0x4 |00000100 # 0068|0x44|01000100
    -123|0x85|10000101 # -059|0xc5|11000101 # 0005|0x5 |00000101 # 0069|0x45|01000101
    -122|0x86|10000110 # -058|0xc6|11000110 # 0006|0x6 |00000110 # 0070|0x46|01000110
    -121|0x87|10000111 # -057|0xc7|11000111 # 0007|0x7 |00000111 # 0071|0x47|01000111
    -120|0x88|10001000 # -056|0xc8|11001000 # 0008|0x8 |00001000 # 0072|0x48|01001000
    -119|0x89|10001001 # -055|0xc9|11001001 # 0009|0x9 |00001001 # 0073|0x49|01001001
    -118|0x8a|10001010 # -054|0xca|11001010 # 0010|0xa |00001010 # 0074|0x4a|01001010
    -117|0x8b|10001011 # -053|0xcb|11001011 # 0011|0xb |00001011 # 0075|0x4b|01001011
    -116|0x8c|10001100 # -052|0xcc|11001100 # 0012|0xc |00001100 # 0076|0x4c|01001100
    -115|0x8d|10001101 # -051|0xcd|11001101 # 0013|0xd |00001101 # 0077|0x4d|01001101
    -114|0x8e|10001110 # -050|0xce|11001110 # 0014|0xe |00001110 # 0078|0x4e|01001110
    -113|0x8f|10001111 # -049|0xcf|11001111 # 0015|0xf |00001111 # 0079|0x4f|01001111
    -112|0x90|10010000 # -048|0xd0|11010000 # 0016|0x10|00010000 # 0080|0x50|01010000
    -111|0x91|10010001 # -047|0xd1|11010001 # 0017|0x11|00010001 # 0081|0x51|01010001
    -110|0x92|10010010 # -046|0xd2|11010010 # 0018|0x12|00010010 # 0082|0x52|01010010
    -109|0x93|10010011 # -045|0xd3|11010011 # 0019|0x13|00010011 # 0083|0x53|01010011
    -108|0x94|10010100 # -044|0xd4|11010100 # 0020|0x14|00010100 # 0084|0x54|01010100
    -107|0x95|10010101 # -043|0xd5|11010101 # 0021|0x15|00010101 # 0085|0x55|01010101
    -106|0x96|10010110 # -042|0xd6|11010110 # 0022|0x16|00010110 # 0086|0x56|01010110
    -105|0x97|10010111 # -041|0xd7|11010111 # 0023|0x17|00010111 # 0087|0x57|01010111
    -104|0x98|10011000 # -040|0xd8|11011000 # 0024|0x18|00011000 # 0088|0x58|01011000
    -103|0x99|10011001 # -039|0xd9|11011001 # 0025|0x19|00011001 # 0089|0x59|01011001
    -102|0x9a|10011010 # -038|0xda|11011010 # 0026|0x1a|00011010 # 0090|0x5a|01011010
    -101|0x9b|10011011 # -037|0xdb|11011011 # 0027|0x1b|00011011 # 0091|0x5b|01011011
    -100|0x9c|10011100 # -036|0xdc|11011100 # 0028|0x1c|00011100 # 0092|0x5c|01011100
    -099|0x9d|10011101 # -035|0xdd|11011101 # 0029|0x1d|00011101 # 0093|0x5d|01011101
    -098|0x9e|10011110 # -034|0xde|11011110 # 0030|0x1e|00011110 # 0094|0x5e|01011110
    -097|0x9f|10011111 # -033|0xdf|11011111 # 0031|0x1f|00011111 # 0095|0x5f|01011111
    -096|0xa0|10100000 # -032|0xe0|11100000 # 0032|0x20|00100000 # 0096|0x60|01100000
    -095|0xa1|10100001 # -031|0xe1|11100001 # 0033|0x21|00100001 # 0097|0x61|01100001
    -094|0xa2|10100010 # -030|0xe2|11100010 # 0034|0x22|00100010 # 0098|0x62|01100010
    -093|0xa3|10100011 # -029|0xe3|11100011 # 0035|0x23|00100011 # 0099|0x63|01100011
    -092|0xa4|10100100 # -028|0xe4|11100100 # 0036|0x24|00100100 # 0100|0x64|01100100
    -091|0xa5|10100101 # -027|0xe5|11100101 # 0037|0x25|00100101 # 0101|0x65|01100101
    -090|0xa6|10100110 # -026|0xe6|11100110 # 0038|0x26|00100110 # 0102|0x66|01100110
    -089|0xa7|10100111 # -025|0xe7|11100111 # 0039|0x27|00100111 # 0103|0x67|01100111
    -088|0xa8|10101000 # -024|0xe8|11101000 # 0040|0x28|00101000 # 0104|0x68|01101000
    -087|0xa9|10101001 # -023|0xe9|11101001 # 0041|0x29|00101001 # 0105|0x69|01101001
    -086|0xaa|10101010 # -022|0xea|11101010 # 0042|0x2a|00101010 # 0106|0x6a|01101010
    -085|0xab|10101011 # -021|0xeb|11101011 # 0043|0x2b|00101011 # 0107|0x6b|01101011
    -084|0xac|10101100 # -020|0xec|11101100 # 0044|0x2c|00101100 # 0108|0x6c|01101100
    -083|0xad|10101101 # -019|0xed|11101101 # 0045|0x2d|00101101 # 0109|0x6d|01101101
    -082|0xae|10101110 # -018|0xee|11101110 # 0046|0x2e|00101110 # 0110|0x6e|01101110
    -081|0xaf|10101111 # -017|0xef|11101111 # 0047|0x2f|00101111 # 0111|0x6f|01101111
    -080|0xb0|10110000 # -016|0xf0|11110000 # 0048|0x30|00110000 # 0112|0x70|01110000
    -079|0xb1|10110001 # -015|0xf1|11110001 # 0049|0x31|00110001 # 0113|0x71|01110001
    -078|0xb2|10110010 # -014|0xf2|11110010 # 0050|0x32|00110010 # 0114|0x72|01110010
    -077|0xb3|10110011 # -013|0xf3|11110011 # 0051|0x33|00110011 # 0115|0x73|01110011
    -076|0xb4|10110100 # -012|0xf4|11110100 # 0052|0x34|00110100 # 0116|0x74|01110100
    -075|0xb5|10110101 # -011|0xf5|11110101 # 0053|0x35|00110101 # 0117|0x75|01110101
    -074|0xb6|10110110 # -010|0xf6|11110110 # 0054|0x36|00110110 # 0118|0x76|01110110
    -073|0xb7|10110111 # -009|0xf7|11110111 # 0055|0x37|00110111 # 0119|0x77|01110111
    -072|0xb8|10111000 # -008|0xf8|11111000 # 0056|0x38|00111000 # 0120|0x78|01111000
    -071|0xb9|10111001 # -007|0xf9|11111001 # 0057|0x39|00111001 # 0121|0x79|01111001
    -070|0xba|10111010 # -006|0xfa|11111010 # 0058|0x3a|00111010 # 0122|0x7a|01111010
    -069|0xbb|10111011 # -005|0xfb|11111011 # 0059|0x3b|00111011 # 0123|0x7b|01111011
    -068|0xbc|10111100 # -004|0xfc|11111100 # 0060|0x3c|00111100 # 0124|0x7c|01111100
    -067|0xbd|10111101 # -003|0xfd|11111101 # 0061|0x3d|00111101 # 0125|0x7d|01111101
    -066|0xbe|10111110 # -002|0xfe|11111110 # 0062|0x3e|00111110 # 0126|0x7e|01111110
    -065|0xbf|10111111 # -001|0xff|11111111 # 0063|0x3f|00111111 # 0127|0x7f|01111111