varch/doc/intl.en.md

7.5 KiB

Introduction

The intl is a large integer module that enables operations on large integers beyond the limits of the standard data types in the C language. It provides a flexible representation of long integers, which are stored using 16-bit and 32-bit segments.

In mainstream computer systems nowadays, the maximum integer generally supported is usually 32 bits or 64 bits, which can meet the calculation and storage requirements in ordinary situations. However, when dealing with even larger numbers, they may fall short. The intl module, as an additional integer extension, adopts a consistent storage mechanism and is quite convenient to use. It offers the following calculations:

  • Supports basic arithmetic operations: addition, subtraction, multiplication, division, and modulo operations.
  • Bitwise operations: AND, OR, XOR, and NOT.
  • Shift operations: left shift and right shift.
  • Functions for converting strings and standard integers into large integers.
  • Provides functions to output large integers in decimal, hexadecimal, and binary formats.

The intl can be configured as needed to be 128 bits, 256 bits, 512 bits, 1024 bits, 2048 bits, 4096 bits, or 8192 bits. If these are still not sufficient, it also provides functions to generate even larger configurations with more bits.

Interface

Structure Definition

intl

It is a structure used to represent long integer values. It uses a union to store integers in two different ways:

  • An array of the uint16_t type (16-bit segments).
  • An array of the uint32_t type (32-bit segments).
typedef struct {
    union {
        uint16_t u16[INTL_U16_PARTS];
        uint32_t u32[INTL_U32_PARTS];
    };
} intl;

Definition Functions

intl intl_from(const char *str);            // 
intl intl_from2(int value);                 //

The intl provides two definition functions.

The intl_from function parses and generates an intl from a numeric string. It supports parsing strings in decimal, binary, octal, and hexadecimal formats. The intl_from2 function creates an intl from an int type. This function is encapsulated into a shorter macro definition method intl(), which is closer to the usage habits and has higher execution efficiency.

Regarding the usage of the two functions, when the value is within the range of int, it is recommended to use the intl() method. When the value exceeds the range of int or when it is necessary to define it in different number systems, the intl_from() method can be used.

Meanwhile, macro definitions for commonly used values such as INTL_MAX, INTL_MIN, and INTL_ZERO are also available.

Example:

static void test_define(void)
{
    intl a = intl(0);
    intl b = intl(10);
    intl c = intl(-10);
    intl d = intl(0xFF);

    intl e = intl_from("0");
    intl f = intl_from("100");
    intl g = intl_from("-100");
    intl h = intl_from("123456789123456789123456789");
    intl i = intl_from("0b1110000001111100101010100");
    intl j = intl_from("0o1236541236763210233642166");
    intl k = intl_from("0xF125E3F6D743648EEFFF12356");

    intl max = INTL_MAX;
    intl min = INTL_MIN;
    intl n0 = INTL_ZERO;
}

Conversion Functions

const char* intl_sdec(intl a, char buffer[INTL_MAX_DEC]);
const char* intl_shex(intl a, char buffer[INTL_MAX_HEX]);
const char* intl_sbin(intl a, char buffer[INTL_MAX_BIN]);

These three functions are used in the same way. They convert the value of a into decimal, hexadecimal, and binary formats respectively and store the results in the passed buffer, and then return the address of the buffer with valid digits.

#define INTL_P_DEC                      0x01
#define INTL_P_BIN                      0x02
#define INTL_P_HEX                      0x04

static void print_intl(intl a, int type) 
{
    char buffer[INTL_MAX_BIN];
    if (type & INTL_P_DEC) printf("intl (decimal): %s\n", intl_sdec(a, buffer));
    if (type & INTL_P_HEX) printf("intl (hex): %s\n", intl_shex(a, buffer));
    if (type & INTL_P_BIN) printf("intl (bin): %s\n", intl_sbin(a, buffer));
}

static void test_print(void)
{
    intl a = intl_from("123456789123456789123456789");

    print_intl(a, INTL_P_DEC);
    print_intl(a, INTL_P_BIN);
    print_intl(a, INTL_P_HEX);
}

Result:

intl (decimal): 123456789123456789123456789
intl (bin): 110011000011110111111011111001011100011101100011001111101111100000001000101111100010101
intl (hex): 661EFDF2E3B19F7C045F15

Operation Functions

intl intl_add(intl a, intl b);              // a+b
intl intl_sub(intl a, intl b);              // a-b
intl intl_mul(intl a, intl b);              // a*b
intl intl_div(intl a, intl b);              // a/b
intl intl_mod(intl a, intl b);              // a%b
intl intl_and(intl a, intl b);              // a&b
intl intl_xor(intl a, intl b);              // a^b
intl intl_or(intl a, intl b);               // a|b
intl intl_shl(intl a, uint32_t amount);     // a<<amount
intl intl_shr(intl a, uint32_t amount);     // a>>amount
intl intl_not(intl a);                      // ~a
intl intl_abs(intl a);                      // |a|
intl intl_inc(intl a);                      // a++
intl intl_dec(intl a);                      // a--
intl intl_neg(intl a);                      // -a
int intl_cmp(intl a, intl b);               // a>b a<b a>=b a<=b
int intl_sign(intl a);                      // a>0 a<0 a==0

The operation functions of intl are consistent with the similar symbolic operations.

Example of Use:

static void test_calculate(void)
{
    intl a = intl_from("123456789123456789123456789");
    intl b = intl_from("987654321987654321987654321");

    printf("a: \r\n");
    print_intl(a, INTL_P_DEC);
    printf("b: \r\n");
    print_intl(b, INTL_P_DEC);

    printf("a + b: \r\n");
    print_intl(intl_add(a, b), INTL_P_DEC);

    printf("a - b: \r\n");
    print_intl(intl_sub(a, b), INTL_P_DEC);

    printf("a * b: \r\n");
    print_intl(intl_mul(a, b), INTL_P_DEC);

    printf("b / a: \r\n");
    print_intl(intl_div(b, a), INTL_P_DEC);

    printf("b %% a: \r\n");
    print_intl(intl_mod(b, a), INTL_P_DEC);

    printf("a & b: \r\n");
    print_intl(intl_and(a, b), INTL_P_DEC);

    printf("a | b: \r\n");
    print_intl(intl_or(a, b), INTL_P_DEC);

    printf("a ^ b: \r\n");
    print_intl(intl_xor(a, b), INTL_P_DEC);

    printf("~a: \r\n");
    print_intl(intl_not(a), INTL_P_DEC);

    printf("a << 1: \r\n");
    print_intl(intl_shl(a, 1), INTL_P_DEC);

    printf("b >> 1: \r\n");
    print_intl(intl_shr(b, 1), INTL_P_DEC);

    printf("compare: %d\r\n", intl_cmp(a, b));

    printf("a incremented: \r\n");
    print_intl(intl_inc(a), INTL_P_DEC);

    printf("b decremented: \r\n");
    print_intl(intl_dec(b), INTL_P_DEC);
}

Result:

a:
intl (decimal): 123456789123456789123456789
b:
intl (decimal): 987654321987654321987654321
a + b:
intl (decimal): 1111111111111111111111111110
a - b:
intl (decimal): -864197532864197532864197532
a * b:
intl (decimal): 121932631356500531591068431581771069347203169112635269
b / a:
intl (decimal): 8
b % a:
intl (decimal): 9000000009000000009
a & b:
intl (decimal): 38793946662829560778723857
a | b:
intl (decimal): 1072317164448281550332387253
a ^ b:
intl (decimal): 1033523217785451989553663396
~a:
intl (decimal): -123456789123456789123456790
a << 1:
intl (decimal): 246913578246913578246913578
b >> 1:
intl (decimal): 493827160993827160993827160
compare: -1
a incremented:
intl (decimal): 123456789123456789123456790
b decremented:
intl (decimal): 987654321987654321987654320