mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-07 01:06:41 +08:00
添加大型整数计算模块intl
This commit is contained in:
parent
fcf3d6dc8f
commit
0c6a112066
@ -29,6 +29,7 @@ It has the characteristics of **simplicity, universality, and efficiency**, with
|
|||||||
| tool | 01.00.00 | [link](/doc/tool.md) | ./source/01_general | General tools code
|
| tool | 01.00.00 | [link](/doc/tool.md) | ./source/01_general | General tools code
|
||||||
| valloc | 01.00.00 | [link](/doc/valloc.md) | ./source/01_general | Dynamic memory usage testing tool
|
| valloc | 01.00.00 | [link](/doc/valloc.md) | ./source/01_general | Dynamic memory usage testing tool
|
||||||
| vlog | 01.01.00 | [link](/doc/vlog.md) | ./source/01_general | Log output module
|
| vlog | 01.01.00 | [link](/doc/vlog.md) | ./source/01_general | Log output module
|
||||||
|
| intl | 01.00.00 | [link](/doc/intl.md) | ./source/01_general | Large integer arithmetic module
|
||||||
| vctype | 01.00.00 | [link](/doc/vctype.md) | ./source/02_vstd | Similar to the C standard library ctype
|
| vctype | 01.00.00 | [link](/doc/vctype.md) | ./source/02_vstd | Similar to the C standard library ctype
|
||||||
| vmath | 01.00.00 | [link](/doc/vmath.md) | ./source/02_vstd | Similar to the C standard library math
|
| vmath | 01.00.00 | [link](/doc/vmath.md) | ./source/02_vstd | Similar to the C standard library math
|
||||||
| vmem | 01.00.00 | [link](/doc/vmem.md) | ./source/02_vstd | Simple implementation of memory pool
|
| vmem | 01.00.00 | [link](/doc/vmem.md) | ./source/02_vstd | Simple implementation of memory pool
|
||||||
|
|||||||
@ -29,6 +29,7 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用
|
|||||||
| tool | 01.00.00 | [link](/doc/tool.md) | ./source/01_general | 通用工具代码
|
| tool | 01.00.00 | [link](/doc/tool.md) | ./source/01_general | 通用工具代码
|
||||||
| valloc | 01.00.00 | [link](/doc/valloc.md) | ./source/01_general | 动态内存使用测试工具
|
| valloc | 01.00.00 | [link](/doc/valloc.md) | ./source/01_general | 动态内存使用测试工具
|
||||||
| vlog | 01.01.00 | [link](/doc/vlog.md) | ./source/01_general | 日志输出模块
|
| vlog | 01.01.00 | [link](/doc/vlog.md) | ./source/01_general | 日志输出模块
|
||||||
|
| intl | 01.00.00 | [link](/doc/intl.md) | ./source/01_general | 大型整数运算模块
|
||||||
| vctype | 01.00.00 | [link](/doc/vctype.md) | ./source/02_vstd | 类似于C标准库ctype
|
| vctype | 01.00.00 | [link](/doc/vctype.md) | ./source/02_vstd | 类似于C标准库ctype
|
||||||
| vmath | 01.00.00 | [link](/doc/vmath.md) | ./source/02_vstd | 类似于C标准库math
|
| vmath | 01.00.00 | [link](/doc/vmath.md) | ./source/02_vstd | 类似于C标准库math
|
||||||
| vmem | 01.00.00 | [link](/doc/vmem.md) | ./source/02_vstd | 内存池的简单实现
|
| vmem | 01.00.00 | [link](/doc/vmem.md) | ./source/02_vstd | 内存池的简单实现
|
||||||
|
|||||||
229
doc/intl.md
Normal file
229
doc/intl.md
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
## 介绍
|
||||||
|
|
||||||
|
`intl`为一个大型整数模块,该模块允许对超过 C 语言标准数据类型限制的大整数进行操作。它提供了一个灵活的长整型表示,使用 16 位和 32 位段来存储。
|
||||||
|
|
||||||
|
现在主流的计算机系统中一般支持的最大整形数为 32bits 或者 64bits 的,其能满足在一般情况下的计算及存储,但是面对一些更大的数时候就会显得有心无力。
|
||||||
|
而`intl`模块作为额外的整型数扩充,采用了一致的存储机制,而且在使用起来也非常方便。提供以下的计算:
|
||||||
|
|
||||||
|
- 支持基本算术操作:加法、减法、乘法、除法和取模。
|
||||||
|
- 位运算:与、或、异或、非。
|
||||||
|
- 移位操作:左移和右移。
|
||||||
|
- 将字符串和标准整数转换为大整数的功能。
|
||||||
|
- 提供以十进制、十六进制和二进制格式输出大整数的函数。
|
||||||
|
|
||||||
|
`intl` 可以按需配置为 128bits、256bits、512bits、1024bits、2048bits、4096bits、8192bits,如果都还不满足,还提供了生成更大bits的函数来生成更大的配置。
|
||||||
|
|
||||||
|
|
||||||
|
## 接口
|
||||||
|
|
||||||
|
## 结构定义
|
||||||
|
|
||||||
|
### `intl`
|
||||||
|
|
||||||
|
一个结构体,用于表示长整型整数,使用联合体以两种不同方式存储整数:
|
||||||
|
|
||||||
|
- 一个 `uint16_t` 类型的数组(16 位段)。
|
||||||
|
- 一个 `uint32_t` 类型的数组(32 位段)。
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
uint16_t u16[INTL_U16_PARTS];
|
||||||
|
uint32_t u32[INTL_U32_PARTS];
|
||||||
|
};
|
||||||
|
} intl;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 定义函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
intl intl_from(const char *str); //
|
||||||
|
intl intl_from2(int value); //
|
||||||
|
```
|
||||||
|
|
||||||
|
`intl`提供了两种定义函数。
|
||||||
|
|
||||||
|
`intl_from`为从数字字符串中解析生成一个`intl`,支持解析十进制、二进制、八进制、十六进制字符串。
|
||||||
|
`intl_from2`为从`int`型中创建一个`intl`,此函数封装成更简短的宏定义方法`intl()`更贴近使用习惯,此方法执行效率更高。
|
||||||
|
|
||||||
|
两者的使用,当值在`int`的取值范围内时,推荐使用`intl()`方法,而当数值超越`int`的取值范围时或者需要不同进制进行定义时,就可以使用`intl_from()`方法。
|
||||||
|
|
||||||
|
同时,也可以使用常用值的宏定义`INTL_MAX`、`INTL_MIN`、`INTL_ZERO`。
|
||||||
|
|
||||||
|
例子:
|
||||||
|
```c
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 转换函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
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]);
|
||||||
|
```
|
||||||
|
|
||||||
|
此三个函数使用方法上是一致的,把`a`的值转换成十进制、十六进制、二进制到传入的`buffer`中,并返回有效位的`buffer`地址。
|
||||||
|
|
||||||
|
```c
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
```
|
||||||
|
intl (decimal): 123456789123456789123456789
|
||||||
|
intl (bin): 110011000011110111111011111001011100011101100011001111101111100000001000101111100010101
|
||||||
|
intl (hex): 661EFDF2E3B19F7C045F15
|
||||||
|
```
|
||||||
|
|
||||||
|
### 运算函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
`intl`运算函数与类似符号运算一致。
|
||||||
|
|
||||||
|
使用例子:
|
||||||
|
```c
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
```
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
975
source/01_general/intl.c
Normal file
975
source/01_general/intl.c
Normal file
@ -0,0 +1,975 @@
|
|||||||
|
/*********************************************************************************************************
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* file description
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* \file intl.c
|
||||||
|
* \unit intl
|
||||||
|
* \brief This is a simple large inter number calculate module for C language
|
||||||
|
* \author Lamdonn
|
||||||
|
* \version v1.0.0
|
||||||
|
* \license GPL-2.0
|
||||||
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
|
********************************************************************************************************/
|
||||||
|
#include "intl.h"
|
||||||
|
|
||||||
|
/* Internal static function declarations */
|
||||||
|
|
||||||
|
static int intl_ucmp(intl a, intl b);
|
||||||
|
static intl intl_umul(intl a, intl b);
|
||||||
|
static intl intl_udiv(intl a, intl b, intl *mod);
|
||||||
|
static intl intl_umod(intl a, intl b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds two intl numbers.
|
||||||
|
*
|
||||||
|
* This function computes the sum of two 128-bit integers
|
||||||
|
* (intl). It processes each 16-bit part of the input integers,
|
||||||
|
* handling carry bits as necessary. The result is stored in a
|
||||||
|
* new intl number. This function ensures that overflow is
|
||||||
|
* correctly managed across all parts.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first operand (intl number).
|
||||||
|
* \param[in] b: The second operand (intl number).
|
||||||
|
* \return The sum of a and b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_add(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result; // Initialize the result variable
|
||||||
|
uint16_t carry = 0; /** Carry bit */
|
||||||
|
|
||||||
|
// Perform addition for each 16-bit part
|
||||||
|
for (int i = 0; i < INTL_U16_PARTS; i++)
|
||||||
|
{
|
||||||
|
// Calculate the sum of corresponding parts and carry
|
||||||
|
uint32_t sum = (uint32_t)a.u16[i] + (uint32_t)b.u16[i] + carry;
|
||||||
|
result.u16[i] = (uint16_t)(sum & 0xFFFF); /** Lower 16 bits */
|
||||||
|
carry = (sum >> 16) & 0xFFFF; /** Upper 16 bits as carry */
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Subtracts one intl number from another.
|
||||||
|
*
|
||||||
|
* This function computes the difference of two 128-bit integers
|
||||||
|
* (intl). It processes each 16-bit part of the minuend and
|
||||||
|
* subtrahend, handling borrow bits as necessary. The result is
|
||||||
|
* stored in a new intl number. This function ensures that
|
||||||
|
* borrowing is correctly managed across all parts.
|
||||||
|
*
|
||||||
|
* \param[in] a: The minuend (the number from which another is to be subtracted).
|
||||||
|
* \param[in] b: The subtrahend (the number to be subtracted).
|
||||||
|
* \return The result of a - b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_sub(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result; // Initialize the result variable
|
||||||
|
|
||||||
|
// Perform subtraction for each 16-bit part
|
||||||
|
for (int i = 0; i < INTL_U16_PARTS; i++)
|
||||||
|
{
|
||||||
|
uint32_t diff = (uint32_t)a.u16[i] - (uint32_t)b.u16[i];
|
||||||
|
|
||||||
|
// Check if a borrow occurred
|
||||||
|
if (diff & 0xFFFF0000) /** Borrow occurred */
|
||||||
|
{
|
||||||
|
// Adjust the higher parts to account for the borrow
|
||||||
|
for (int j = i + 1; j < INTL_U16_PARTS; j++)
|
||||||
|
{
|
||||||
|
a.u16[j] -= 1; // Borrow from the next part
|
||||||
|
if (a.u16[j] != 0xFFFF) break; // Stop if no further borrow needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the result of the subtraction
|
||||||
|
result.u16[i] = (uint16_t)(diff & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Increments the intl number by one.
|
||||||
|
*
|
||||||
|
* This function increments a 128-bit integer (intl) by one.
|
||||||
|
* It processes each 32-bit part of the input integer and
|
||||||
|
* handles carry bits as necessary. The function continues
|
||||||
|
* to increment the subsequent parts until there is no overflow.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to increment.
|
||||||
|
* \return The incremented intl number as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_inc(intl a)
|
||||||
|
{
|
||||||
|
// Increment each 32-bit part of the intl number
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
a.u32[i]++; // Increment the current part
|
||||||
|
// Check if the current part overflowed
|
||||||
|
if (a.u32[i] != 0)
|
||||||
|
{
|
||||||
|
break; /** Return immediately if no overflow */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a; /** Return the incremented result */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decrements the intl number by one.
|
||||||
|
*
|
||||||
|
* This function decrements a 128-bit integer (intl) by one.
|
||||||
|
* It processes each 32-bit part of the input integer, handling
|
||||||
|
* borrowing as necessary. If the current part is zero, it sets
|
||||||
|
* that part to its maximum value (0xFFFFFFFF) and continues
|
||||||
|
* to the next part to borrow from it.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to decrement.
|
||||||
|
* \return The decremented intl number as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_dec(intl a)
|
||||||
|
{
|
||||||
|
// Decrement each 32-bit part of the intl number
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
// Check if the current part can be decremented
|
||||||
|
if (a.u32[i] != 0)
|
||||||
|
{
|
||||||
|
a.u32[i]--; // Decrement the current part
|
||||||
|
break; /** Return immediately if current part can be decremented */
|
||||||
|
}
|
||||||
|
// If current part is zero, set it to max value and continue borrowing
|
||||||
|
a.u32[i] = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
return a; /** Return the decremented result */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies two intl unsigned numbers.
|
||||||
|
*
|
||||||
|
* This function performs multiplication of two 128-bit unsigned integers
|
||||||
|
* (intl) by using a method similar to the schoolbook algorithm. The
|
||||||
|
* multiplication is carried out by breaking the numbers into their
|
||||||
|
* 16-bit components and accumulating the results. The function handles
|
||||||
|
* carry-over during the multiplication and addition stages to ensure
|
||||||
|
* the final product is accurately represented.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first operand to multiply.
|
||||||
|
* \param[in] b: The second operand to multiply.
|
||||||
|
* \return The product of a and b as an intl (128-bit unsigned integer).
|
||||||
|
*/
|
||||||
|
static intl intl_umul(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result = {0}; /** Initialize the result to 0 */
|
||||||
|
intl temp[INTL_U16_PARTS] = {{0}}; // Temporary storage for intermediate results
|
||||||
|
uint16_t carry = 0; // Variable to hold carry-over during multiplication
|
||||||
|
|
||||||
|
// Perform multiplication
|
||||||
|
for (int i = 0; i < INTL_U16_PARTS; i++)
|
||||||
|
{
|
||||||
|
carry = 0; // Reset carry for the current row
|
||||||
|
for (int j = 0; j < INTL_U16_PARTS; j++)
|
||||||
|
{
|
||||||
|
if (i + j < INTL_U16_PARTS)
|
||||||
|
{
|
||||||
|
// Multiply the 16-bit segments and add carry
|
||||||
|
uint32_t mul = (uint32_t)a.u16[i] * (uint32_t)b.u16[j] + carry;
|
||||||
|
temp[i].u16[i + j] = (mul & 0xFFFF); // Store the lower 16 bits
|
||||||
|
carry = ((mul >> 16) & 0xFFFF); // Update carry for the next addition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
carry = 0; // Reset carry for the addition phase
|
||||||
|
// Combine results from the temporary storage
|
||||||
|
for (int i = 0; i < INTL_U16_PARTS; i++)
|
||||||
|
{
|
||||||
|
uint32_t add = 0; // Variable to hold the sum of the current column
|
||||||
|
for (int j = 0; j < INTL_U16_PARTS; j++)
|
||||||
|
{
|
||||||
|
add += temp[j].u16[i]; // Accumulate results from temp
|
||||||
|
}
|
||||||
|
add += carry; // Add any carry from the previous column
|
||||||
|
result.u16[i] = (add & 0xFFFF); // Store the lower 16 bits in result
|
||||||
|
carry = ((add >> 16) & 0xFFFF); // Update carry for the next column
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; // Return the final product
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multiplies two intl numbers.
|
||||||
|
*
|
||||||
|
* This function multiplies two 128-bit integers (intl) and returns
|
||||||
|
* the product as another intl number. It handles signed multiplication
|
||||||
|
* by checking the sign of the operands. If either operand is negative,
|
||||||
|
* it negates the operand and adjusts the sign of the result accordingly.
|
||||||
|
* The actual multiplication is performed using the `intl_umul`
|
||||||
|
* function, which handles the absolute values of the integers.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first operand to multiply.
|
||||||
|
* \param[in] b: The second operand to multiply.
|
||||||
|
* \return The product of a and b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_mul(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result = {0}; // Initialize the result to 0
|
||||||
|
int sign = 1; // Variable to track the sign of the result
|
||||||
|
|
||||||
|
// Check and handle the sign of the first operand
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
{
|
||||||
|
sign = -sign; // Negate the sign for the result
|
||||||
|
a = intl_neg(a); // Negate the first operand
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and handle the sign of the second operand
|
||||||
|
if (b.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
{
|
||||||
|
sign = -sign; // Negate the sign for the result
|
||||||
|
b = intl_neg(b); // Negate the second operand
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform unsigned multiplication
|
||||||
|
result = intl_umul(a, b);
|
||||||
|
|
||||||
|
// If the result should be negative, negate it
|
||||||
|
if (sign < 0)
|
||||||
|
result = intl_neg(result);
|
||||||
|
|
||||||
|
return result; // Return the final product
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Divides one intl unsigned number by another.
|
||||||
|
*
|
||||||
|
* This function performs division of one 128-bit unsigned integer (intl)
|
||||||
|
* by another. It calculates the quotient using a bitwise approach,
|
||||||
|
* handling division by zero gracefully. The result is built bit by bit
|
||||||
|
* from the most significant bit to the least significant bit. If the
|
||||||
|
* divisor is zero, it prints an error message and returns zero.
|
||||||
|
*
|
||||||
|
* \param[in] a: The dividend (number to be divided).
|
||||||
|
* \param[in] b: The divisor (number to divide by).
|
||||||
|
* \return The quotient of a divided by b as an intl (128-bit unsigned integer).
|
||||||
|
*/
|
||||||
|
static intl intl_udiv(intl a, intl b, intl *mod)
|
||||||
|
{
|
||||||
|
// Check for division by zero
|
||||||
|
if (intl_sign(b) == 0)
|
||||||
|
{
|
||||||
|
printf("Division by zero!\n");
|
||||||
|
return (intl){0}; /** Handle division by zero */
|
||||||
|
}
|
||||||
|
|
||||||
|
intl result = {0}; // Initialize the result to zero
|
||||||
|
intl remainder = {0}; // Initialize the remainder to zero
|
||||||
|
|
||||||
|
/** Calculate bit by bit from the highest bit */
|
||||||
|
for (int i = INTL_BIT_PARTS - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
/** Left shift remainder and add current bit */
|
||||||
|
remainder = intl_shl(remainder, 1); // Shift remainder left by 1
|
||||||
|
remainder.u32[0] |= (a.u32[i / 32] >> (i % 32)) & 1; // Add current bit from dividend
|
||||||
|
|
||||||
|
/** If remainder is greater than or equal to b, subtract b */
|
||||||
|
if (intl_ucmp(remainder, b) >= 0)
|
||||||
|
{
|
||||||
|
remainder = intl_sub(remainder, b); // Subtract b from remainder
|
||||||
|
result.u32[i / 32] |= (1 << (i % 32)); // Set corresponding bit in result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod) *mod = remainder;
|
||||||
|
|
||||||
|
return result; // Return the final quotient
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Divides one intl number by another.
|
||||||
|
*
|
||||||
|
* This function performs division of two 128-bit integers (intl)
|
||||||
|
* and returns the quotient as another intl number. It handles signed
|
||||||
|
* division by checking the sign of the operands. If either operand
|
||||||
|
* is negative, it negates the operand and adjusts the sign of the
|
||||||
|
* result accordingly. The actual division is performed using the
|
||||||
|
* `intl_udiv` function, which handles the absolute values of
|
||||||
|
* the integers.
|
||||||
|
*
|
||||||
|
* \param[in] a: The dividend (number to be divided).
|
||||||
|
* \param[in] b: The divisor (number to divide by).
|
||||||
|
* \return The quotient of a divided by b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_div(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result = {0}; // Initialize the result to 0
|
||||||
|
int sign = 1; // Variable to track the sign of the result
|
||||||
|
|
||||||
|
// Check and handle the sign of the dividend
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
{
|
||||||
|
sign = -sign; // Negate the sign for the result
|
||||||
|
a = intl_neg(a); // Negate the dividend
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and handle the sign of the divisor
|
||||||
|
if (b.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
{
|
||||||
|
sign = -sign; // Negate the sign for the result
|
||||||
|
b = intl_neg(b); // Negate the divisor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform unsigned division
|
||||||
|
result = intl_udiv(a, b, NULL);
|
||||||
|
|
||||||
|
// If the result should be negative, negate it
|
||||||
|
if (sign < 0)
|
||||||
|
result = intl_neg(result);
|
||||||
|
|
||||||
|
return result; // Return the final quotient
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes the remainder of the division of two unsigned intl numbers.
|
||||||
|
*
|
||||||
|
* This function calculates the remainder of the division of two
|
||||||
|
* 128-bit unsigned integers (intl). It uses a bitwise approach to
|
||||||
|
* compute the remainder by processing each bit from the most significant
|
||||||
|
* to the least significant. If the divisor is zero, it handles the
|
||||||
|
* error gracefully by printing a message and returning zero.
|
||||||
|
*
|
||||||
|
* \param[in] a: The dividend (number to be divided).
|
||||||
|
* \param[in] b: The divisor (number to divide by).
|
||||||
|
* \return The remainder of a divided by b as an intl (128-bit unsigned integer).
|
||||||
|
*/
|
||||||
|
static intl intl_umod(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl mod = {0};
|
||||||
|
intl_udiv(a, b, &mod);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes the remainder of the division of two intl numbers.
|
||||||
|
*
|
||||||
|
* This function calculates the remainder of the division of two
|
||||||
|
* 128-bit integers (intl). It handles signed integers by checking
|
||||||
|
* the sign of the dividend. If the dividend is negative, it negates
|
||||||
|
* the dividend before performing the unsigned modulus operation.
|
||||||
|
* The sign of the result is adjusted based on the sign of the
|
||||||
|
* dividend. The actual remainder calculation is performed using the
|
||||||
|
* `intl_umod` function, which handles the absolute values of
|
||||||
|
* the integers.
|
||||||
|
*
|
||||||
|
* \param[in] a: The dividend (number to be divided).
|
||||||
|
* \param[in] b: The divisor (number to divide by).
|
||||||
|
* \return The remainder of a divided by b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_mod(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result = {0}; // Initialize result to zero
|
||||||
|
int sign = 1; // Variable to track the sign of the result
|
||||||
|
|
||||||
|
// Check and handle the sign of the dividend
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
{
|
||||||
|
sign = -sign; // Negate the sign for the result
|
||||||
|
a = intl_neg(a); // Negate the dividend
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform unsigned modulus with the absolute value of the divisor
|
||||||
|
result = intl_umod(a, intl_abs(b));
|
||||||
|
|
||||||
|
// If the result should be negative, negate it
|
||||||
|
if (sign < 0)
|
||||||
|
result = intl_neg(result);
|
||||||
|
|
||||||
|
return result; // Return the final remainder
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Left shifts an intl number by a specified number of bits.
|
||||||
|
*
|
||||||
|
* This function performs a left bitwise shift on a 128-bit integer
|
||||||
|
* (intl). The shift amount can be greater than 32 bits, in which case
|
||||||
|
* the function calculates how many whole 32-bit parts to shift and
|
||||||
|
* how many bits to shift within the remaining part. It constructs
|
||||||
|
* the result based on the input number after applying the shift.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to shift.
|
||||||
|
* \param[in] amount: The number of bits to shift to the left.
|
||||||
|
* \return The left-shifted intl number.
|
||||||
|
*/
|
||||||
|
intl intl_shl(intl a, uint32_t amount)
|
||||||
|
{
|
||||||
|
intl result = {0}; // Initialize the result to zero
|
||||||
|
int u32bias = amount / 32; // Number of whole 32-bit parts to shift
|
||||||
|
int bitsbias = amount % 32; // Remaining bits to shift
|
||||||
|
|
||||||
|
// Perform the shift for each 32-bit part of the intl number
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
if (i < u32bias)
|
||||||
|
{
|
||||||
|
result.u32[i] = 0; // Set shifted-out parts to zero
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Shift the current part and add bits from the previous part if needed
|
||||||
|
result.u32[i] = (a.u32[i - u32bias] << bitsbias) |
|
||||||
|
(((i - u32bias - 1) >= 0 && bitsbias > 0) ?
|
||||||
|
(a.u32[i - u32bias - 1] >> (32 - bitsbias)) : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result; // Return the left-shifted result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Right shifts an intl number by a specified number of bits.
|
||||||
|
*
|
||||||
|
* This function performs a right bitwise shift on a 128-bit integer
|
||||||
|
* (intl). The shift amount can be greater than 32 bits, in which case
|
||||||
|
* the function calculates how many whole 32-bit parts to shift and
|
||||||
|
* how many bits to shift within the remaining part. It constructs
|
||||||
|
* the result based on the input number after applying the shift.
|
||||||
|
* The sign bit is preserved for signed shifts.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to shift.
|
||||||
|
* \param[in] amount: The number of bits to shift to the right.
|
||||||
|
* \return The right-shifted intl number.
|
||||||
|
*/
|
||||||
|
intl intl_shr(intl a, uint32_t amount)
|
||||||
|
{
|
||||||
|
intl result = {0}; // Initialize the result to zero
|
||||||
|
int u32bias = amount / 32; // Number of whole 32-bit parts to shift
|
||||||
|
int bitsbias = amount % 32; // Remaining bits to shift
|
||||||
|
|
||||||
|
// Perform the shift for each 32-bit part of the intl number
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
// Check if the current index is beyond the range for valid shifts
|
||||||
|
if (i > INTL_U32_PARTS - u32bias - 1 && INTL_U32_PARTS - u32bias - 1 > 0)
|
||||||
|
{
|
||||||
|
result.u32[i] = 0; // Set shifted-out parts to zero
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Shift the current part and add bits from the next part if needed
|
||||||
|
result.u32[i] = (a.u32[i + u32bias] >> bitsbias) |
|
||||||
|
(((i + u32bias + 1) < INTL_U32_PARTS && bitsbias > 0) ?
|
||||||
|
(a.u32[i + u32bias + 1] << (32 - bitsbias)) :
|
||||||
|
((a.u32[INTL_U32_PARTS - 1] & 0x80000000) ? 0xFFFFFFFF : 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; // Return the right-shifted result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Performs bitwise AND operation on two intl numbers.
|
||||||
|
*
|
||||||
|
* This function computes the bitwise AND of two 128-bit integers
|
||||||
|
* (intl). It processes each 32-bit part of the input integers and
|
||||||
|
* performs the AND operation on corresponding parts, storing the
|
||||||
|
* result in a new intl number. This operation yields a number that
|
||||||
|
* has bits set only where both operands have bits set.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first operand (intl number).
|
||||||
|
* \param[in] b: The second operand (intl number).
|
||||||
|
* \return The result of a AND b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_and(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result; // Initialize the result variable
|
||||||
|
// Perform the bitwise AND operation for each 32-bit part
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
result.u32[i] = a.u32[i] & b.u32[i]; // Compute AND for each part
|
||||||
|
}
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Performs bitwise OR operation on two intl numbers.
|
||||||
|
*
|
||||||
|
* This function computes the bitwise OR of two 128-bit integers
|
||||||
|
* (intl). It processes each 32-bit part of the input integers and
|
||||||
|
* performs the OR operation on corresponding parts, storing the
|
||||||
|
* result in a new intl number. This operation yields a number that
|
||||||
|
* has bits set where at least one of the operands has bits set.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first operand (intl number).
|
||||||
|
* \param[in] b: The second operand (intl number).
|
||||||
|
* \return The result of a OR b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_or(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result; // Initialize the result variable
|
||||||
|
// Perform the bitwise OR operation for each 32-bit part
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
result.u32[i] = a.u32[i] | b.u32[i]; // Compute OR for each part
|
||||||
|
}
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Performs bitwise XOR operation on two intl numbers.
|
||||||
|
*
|
||||||
|
* This function computes the bitwise XOR of two 128-bit integers
|
||||||
|
* (intl). It processes each 32-bit part of the input integers and
|
||||||
|
* performs the XOR operation on corresponding parts, storing the
|
||||||
|
* result in a new intl number. This operation yields a number that
|
||||||
|
* has bits set where only one of the operands has bits set.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first operand (intl number).
|
||||||
|
* \param[in] b: The second operand (intl number).
|
||||||
|
* \return The result of a XOR b as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_xor(intl a, intl b)
|
||||||
|
{
|
||||||
|
intl result; // Initialize the result variable
|
||||||
|
// Perform the bitwise XOR operation for each 32-bit part
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
result.u32[i] = a.u32[i] ^ b.u32[i]; // Compute XOR for each part
|
||||||
|
}
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Performs bitwise NOT operation on an intl number.
|
||||||
|
*
|
||||||
|
* This function computes the bitwise NOT (negation) of a 128-bit
|
||||||
|
* integer (intl). It processes each 32-bit part of the input integer
|
||||||
|
* and applies the NOT operation, storing the result in a new intl
|
||||||
|
* number. This operation inverts all bits of the input number.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to negate.
|
||||||
|
* \return The bitwise negation of a as an intl (128-bit integer).
|
||||||
|
*/
|
||||||
|
intl intl_not(intl a)
|
||||||
|
{
|
||||||
|
intl result; // Initialize the result variable
|
||||||
|
// Perform the bitwise NOT operation for each 32-bit part
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
result.u32[i] = ~a.u32[i]; // Compute NOT for each part
|
||||||
|
}
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes the absolute value of an intl number.
|
||||||
|
*
|
||||||
|
* This function checks if the given 128-bit unsigned integer (intl)
|
||||||
|
* represents a negative value in two's complement representation.
|
||||||
|
* If the most significant bit (sign bit) of the highest 32-bit segment
|
||||||
|
* is set, it indicates a negative number, and the function calls
|
||||||
|
* intl_neg to return its positive equivalent. If the number is
|
||||||
|
* already non-negative, it simply returns the original number.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number for which to compute the absolute value.
|
||||||
|
* \return The absolute value of the intl number a.
|
||||||
|
*/
|
||||||
|
intl intl_abs(intl a)
|
||||||
|
{
|
||||||
|
// Check if the sign bit of the highest 32-bit part is set
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
return intl_neg(a); // Return negated value if negative
|
||||||
|
return a; // Return the original value if non-negative
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Converts a string to an intl number.
|
||||||
|
*
|
||||||
|
* This function converts a string representation of a number
|
||||||
|
* in various bases (decimal, binary, octal, hexadecimal)
|
||||||
|
* into a 128-bit integer (intl). It handles optional signs
|
||||||
|
* and base prefixes, and processes the string from the end to
|
||||||
|
* the start for efficiency in base conversions.
|
||||||
|
*
|
||||||
|
* \param[in] str: The string to convert.
|
||||||
|
* \return The converted intl number. Returns zero if the
|
||||||
|
* string is invalid or represents zero.
|
||||||
|
*/
|
||||||
|
intl intl_from(const char *str)
|
||||||
|
{
|
||||||
|
const uint8_t ttable[4] = {10, 2, 8, 16}; // Table of digit limits for each base
|
||||||
|
const uint8_t btable[4] = {0, 1, 3, 4}; // Table of bit shifts for each base
|
||||||
|
uint32_t type = 0; // 0 - decimal, 1 - binary, 2 - octal, 3 - hexadecimal
|
||||||
|
intl result = {0}; // Resulting intl number
|
||||||
|
intl base = intl(1); /** Base initialized to 1 */
|
||||||
|
int sign = 1; // Sign of the number (1 for positive, -1 for negative)
|
||||||
|
const char *p = str; // Pointer to traverse the input string
|
||||||
|
|
||||||
|
// Determine the number type based on the string prefix
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case '0': {
|
||||||
|
if (p[1] == 0) { return (intl){0}; } // Handle case of "0"
|
||||||
|
else if (p[1] == 'x' || p[1] == 'X') type = 3; // Hexadecimal
|
||||||
|
else if (p[1] == 'o' || p[1] == 'O') type = 2; // Octal
|
||||||
|
else if (p[1] == 'b' || p[1] == 'B') type = 1; // Binary
|
||||||
|
else if (p[1] < '0' || p[1] >= '0' + ttable[type]) return (intl){0};
|
||||||
|
p += 2; // Move past the prefix
|
||||||
|
} break;
|
||||||
|
case '-': { sign = -1; } // Handle negative sign
|
||||||
|
case '+': { p++; } break; // Handle positive sign
|
||||||
|
default:
|
||||||
|
break; // No sign or prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t len = strlen(p); // Length of the number string
|
||||||
|
const char *s = &p[len - 1]; // Pointer to the last character of the number string
|
||||||
|
|
||||||
|
// Process decimal numbers
|
||||||
|
if (type == 0)
|
||||||
|
{
|
||||||
|
while (s >= p) // Traverse the string backwards
|
||||||
|
{
|
||||||
|
char c = *s;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
uint32_t num = c - '0'; /** Convert character to number */
|
||||||
|
|
||||||
|
/** Process current digit */
|
||||||
|
intl addend = intl_umul(base, (intl){num}); // Multiply base by the digit
|
||||||
|
result = intl_add(result, addend); // Add to result
|
||||||
|
|
||||||
|
/** Multiply base by 10 for the next digit */
|
||||||
|
base = intl_umul(base, (intl){10});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Invalid character in input string: %c\n", *s); // Error handling
|
||||||
|
return (intl){0}; // Return zero for invalid input
|
||||||
|
}
|
||||||
|
s--; // Move to the previous character
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign == -1) // Apply sign if negative
|
||||||
|
{
|
||||||
|
result = intl_neg(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Process non-decimal bases (binary, octal, hexadecimal)
|
||||||
|
uint8_t bit = 0; // Bit position within the current u32 part
|
||||||
|
int index = 0; // Current index in the result array
|
||||||
|
while (s >= p && index < INTL_U32_PARTS)
|
||||||
|
{
|
||||||
|
char c = *s;
|
||||||
|
// Adjust character for hex representation
|
||||||
|
if (c >= 'A' && c <= 'F') c -= 7; // A-F to 10-15
|
||||||
|
else if (c >= 'a' && c <= 'f') c -= 39; // a-f to 10-15
|
||||||
|
|
||||||
|
// Validate and process the character
|
||||||
|
if (c >= '0' && c < ('0' + ttable[type]))
|
||||||
|
{
|
||||||
|
result.u32[index] |= ((c - '0') << bit); // Set the value in the corresponding bit
|
||||||
|
bit += btable[type]; // Update the bit position
|
||||||
|
if (bit >= 32) // If bit exceeds 32, move to the next part
|
||||||
|
{
|
||||||
|
bit -= 32; // Reset bit position
|
||||||
|
index++; // Move to the next u32 part
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Invalid character in input string: %c\n", *s); // Error handling
|
||||||
|
return (intl){0}; // Return zero for invalid input
|
||||||
|
}
|
||||||
|
s--; // Move to the previous character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; // Return the resulting intl number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Converts a 32-bit unsigned integer to an intl number.
|
||||||
|
*
|
||||||
|
* This function initializes the first 32-bit segment of the intl structure
|
||||||
|
* with the provided 32-bit unsigned integer value, while the other segments
|
||||||
|
* are set to zero. This allows for easy conversion from a standard integer type
|
||||||
|
* to the custom 128-bit representation.
|
||||||
|
*
|
||||||
|
* \param[in] value: The 32-bit unsigned integer to convert.
|
||||||
|
* \return The corresponding intl number initialized with the given value.
|
||||||
|
*/
|
||||||
|
intl intl_from2(int value)
|
||||||
|
{
|
||||||
|
intl result = {0};
|
||||||
|
memcpy(&result, &value, sizeof(value));
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
memset(((char *)(&result)) + sizeof(value), -1, sizeof(result) - sizeof(value));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Determines the sign of an intl number.
|
||||||
|
*
|
||||||
|
* This function checks the sign of the given 128-bit unsigned integer
|
||||||
|
* (intl) based on its representation. It first examines the most significant
|
||||||
|
* bit of the highest 32-bit segment to determine if the number is negative.
|
||||||
|
* If this bit is set, the function returns -1, indicating a negative value.
|
||||||
|
* If all segments are zero, it returns 0, indicating that the number is zero.
|
||||||
|
* If the number is positive, it returns 1.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to evaluate for its sign.
|
||||||
|
* \return -1 if the number is negative, 0 if the number is zero, and
|
||||||
|
* 1 if the number is positive.
|
||||||
|
*/
|
||||||
|
int intl_sign(intl a)
|
||||||
|
{
|
||||||
|
// Check if the sign bit of the highest 32-bit part is set
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) return -1;
|
||||||
|
|
||||||
|
// Check if the number is zero
|
||||||
|
for (int i = INTL_U32_PARTS - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (a.u32[i] != 0) return 1; // Return 1 if any part is non-zero
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Return 0 if all parts are zero
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Converts an intl number to a decimal string.
|
||||||
|
*
|
||||||
|
* This function converts a 128-bit integer (intl) into its
|
||||||
|
* decimal string representation. The resulting string is
|
||||||
|
* constructed by repeatedly dividing the number by 10 and
|
||||||
|
* storing the remainders. The function handles both positive
|
||||||
|
* and negative integers, including the special case where the
|
||||||
|
* number is zero.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to convert.
|
||||||
|
* \param[out] buffer: The buffer to store the resulting decimal string.
|
||||||
|
*
|
||||||
|
* \return A pointer to the resulting decimal string.
|
||||||
|
*/
|
||||||
|
const char* intl_sdec(intl a, char buffer[INTL_MAX_DEC])
|
||||||
|
{
|
||||||
|
intl ten = intl(10); /** Base 10 for conversion */
|
||||||
|
intl remainder; // To hold the remainder during division
|
||||||
|
intl temp = a; // Temporary variable for manipulation
|
||||||
|
char *p = buffer; // Pointer for writing to the buffer
|
||||||
|
|
||||||
|
// Check if the number is negative
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) // Check sign bit
|
||||||
|
{
|
||||||
|
temp = intl_neg(a); // Negate the number for conversion
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculate decimal string of intl */
|
||||||
|
while (intl_ucmp(temp, (intl){0}) > 0) // While the number is positive
|
||||||
|
{
|
||||||
|
remainder = intl_umod(temp, ten); // Get remainder when divided by 10
|
||||||
|
char digit = '0' + remainder.u32[0]; // Convert remainder to character
|
||||||
|
*p++ = digit; // Store character in buffer
|
||||||
|
temp = intl_udiv(temp, ten, NULL); // Update temp for integer division by 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle special case for 0
|
||||||
|
if (p == buffer)
|
||||||
|
{
|
||||||
|
*p++ = '0'; // If no digits were added, it's zero
|
||||||
|
*p = 0; // Null-terminate the string
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the original number was negative, add '-' sign
|
||||||
|
if (a.u32[INTL_U32_PARTS - 1] & 0x80000000)
|
||||||
|
{
|
||||||
|
*p++ = '-'; // Append negative sign
|
||||||
|
}
|
||||||
|
*p-- = 0; // Null-terminate the string
|
||||||
|
|
||||||
|
// Reverse the string to correct the order of digits
|
||||||
|
char *s = buffer; // Pointer to the start of the buffer
|
||||||
|
while (s < p) // Swap characters
|
||||||
|
{
|
||||||
|
char t = *s; // Temporary variable for swapping
|
||||||
|
*s = *p; // Swap start and end
|
||||||
|
*p = t;
|
||||||
|
s++; // Move pointers towards the center
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer; // Return the resulting decimal string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Converts an intl number to a hexadecimal string.
|
||||||
|
*
|
||||||
|
* This function converts a 128-bit integer (intl) into a
|
||||||
|
* hexadecimal string representation. The resulting string is
|
||||||
|
* formatted as a sequence of hexadecimal digits, with each
|
||||||
|
* part of the intl number contributing 8 digits to the final
|
||||||
|
* string. The string is stored in the provided buffer.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to convert.
|
||||||
|
* \param[out] buffer: The buffer to store the resulting hexadecimal string.
|
||||||
|
*
|
||||||
|
* \return A pointer to the resulting hexadecimal string.
|
||||||
|
*/
|
||||||
|
const char* intl_shex(intl a, char buffer[INTL_MAX_HEX])
|
||||||
|
{
|
||||||
|
char temp[9]; /** Temporary buffer for each part (8 hex digits + null terminator) */
|
||||||
|
char skip = 1; /** Skip invalid 0 */
|
||||||
|
char *p = buffer;
|
||||||
|
|
||||||
|
buffer[0] = '\0'; /** Initialize as empty string */
|
||||||
|
|
||||||
|
// Convert each part of the intl number to hexadecimal, starting from the least significant part
|
||||||
|
for (int i = INTL_U32_PARTS - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (skip == 1)
|
||||||
|
{
|
||||||
|
if (a.u32[i] != 0) skip = 0;
|
||||||
|
else continue; /** Prevent leading zero */
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(temp, sizeof(temp), "%08X", a.u32[i]); /** Convert to hex and store in temp */
|
||||||
|
strcat(p, temp); /** Append converted hex to the result string */
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Prevent leading zero */
|
||||||
|
while (*buffer == '0') buffer++; // Uncomment this line to remove leading zeros
|
||||||
|
|
||||||
|
/** a == 0, print 0 only */
|
||||||
|
if (p == buffer)
|
||||||
|
{
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer; /** Return the resulting hexadecimal string */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Converts an intl number to a binary string.
|
||||||
|
*
|
||||||
|
* This function converts a given 128-bit unsigned integer (intl)
|
||||||
|
* into a binary string representation. It extracts each bit of the
|
||||||
|
* integer and stores the corresponding '0' or '1' character in the
|
||||||
|
* provided buffer. The resulting string is left-aligned, with leading
|
||||||
|
* zeros trimmed.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to convert.
|
||||||
|
* \param[out] buffer: The buffer to store the resulting binary string.
|
||||||
|
* It should be large enough to hold the binary
|
||||||
|
* representation (at least INTL_MAX_BIN characters).
|
||||||
|
* \return A pointer to the first non-zero character in the binary string,
|
||||||
|
* or a pointer to the buffer if the number is zero.
|
||||||
|
*/
|
||||||
|
const char* intl_sbin(intl a, char buffer[INTL_MAX_BIN])
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
uint8_t *base = (uint8_t *)&a; // Cast intl to a byte array
|
||||||
|
int width = sizeof(a); // Get the size of intl
|
||||||
|
char *p = buffer; // Pointer to the current position in buffer
|
||||||
|
|
||||||
|
// Convert each byte to binary
|
||||||
|
for (i = width - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
for (j = 7; j >= 0; j--)
|
||||||
|
{
|
||||||
|
*p++ = (((base[i]) >> (j) & 1) ? '1' : '0'); // Extract bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p = 0; // Null-terminate the string
|
||||||
|
|
||||||
|
// Trim leading zeros and find the first '1'
|
||||||
|
while (buffer < p - 1)
|
||||||
|
{
|
||||||
|
if (*buffer == '1') break; // Stop at the first '1'
|
||||||
|
buffer++; // Skip leading zeros
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer; // Return pointer to the trimmed string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compares two intl unsigned numbers.
|
||||||
|
*
|
||||||
|
* This function compares two 128-bit unsigned integers (intl)
|
||||||
|
* by examining each 32-bit segment from the most significant to
|
||||||
|
* the least significant. It returns 1 if the first number is
|
||||||
|
* greater than the second, -1 if it is less, and 0 if they are
|
||||||
|
* equal. The comparison is done in a way that respects the
|
||||||
|
* unsigned nature of the integers.
|
||||||
|
*
|
||||||
|
* \param[in] a: The first number to compare.
|
||||||
|
* \param[in] b: The second number to compare.
|
||||||
|
* \return 1 if a > b, -1 if a < b, and 0 if a == b.
|
||||||
|
*/
|
||||||
|
static int intl_ucmp(intl a, intl b)
|
||||||
|
{
|
||||||
|
// Compare each 32-bit part from the most significant to the least significant
|
||||||
|
for (int i = INTL_U32_PARTS - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (a.u32[i] > b.u32[i]) return 1; // a is greater
|
||||||
|
if (a.u32[i] < b.u32[i]) return -1; // a is less
|
||||||
|
}
|
||||||
|
return 0; // a and b are equal
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compares two intl numbers.
|
||||||
|
*
|
||||||
|
* This function compares two 128-bit integers (intl) and
|
||||||
|
* determines their relative order. The comparison is performed
|
||||||
|
* starting from the most significant part (highest order) to
|
||||||
|
* the least significant part (lowest order).
|
||||||
|
*
|
||||||
|
* \param[in] a: The first number to compare.
|
||||||
|
* \param[in] b: The second number to compare.
|
||||||
|
*
|
||||||
|
* \return 1 if a > b, -1 if a < b, 0 if a == b.
|
||||||
|
*/
|
||||||
|
int intl_cmp(intl a, intl b)
|
||||||
|
{
|
||||||
|
// Compare each 32-bit part from the most significant to the least significant
|
||||||
|
for (int i = INTL_U32_PARTS - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
// Compare the current parts as signed integers
|
||||||
|
if ((int32_t)a.u32[i] > (int32_t)b.u32[i]) return 1; // a is greater
|
||||||
|
if ((int32_t)a.u32[i] < (int32_t)b.u32[i]) return -1; // a is less
|
||||||
|
}
|
||||||
|
return 0; // a is equal to b
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes the two's complement (negation) of an intl number.
|
||||||
|
*
|
||||||
|
* This function calculates the negative representation of a given 128-bit
|
||||||
|
* unsigned integer (intl) using two's complement. It first inverts all bits
|
||||||
|
* of the input number and then adds one to the result. This effectively
|
||||||
|
* represents the negative value of the original number in a signed
|
||||||
|
* integer format.
|
||||||
|
*
|
||||||
|
* \param[in] a: The intl number to negate.
|
||||||
|
* \return The negated intl number (two's complement of a).
|
||||||
|
*/
|
||||||
|
intl intl_neg(intl a)
|
||||||
|
{
|
||||||
|
intl result = {0};
|
||||||
|
|
||||||
|
// First, bitwise NOT (invert) the input number
|
||||||
|
for (int i = 0; i < INTL_U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
result.u32[i] = ~a.u32[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add one to complete the two's complement operation
|
||||||
|
return intl_inc(result);
|
||||||
|
}
|
||||||
|
|
||||||
82
source/01_general/intl.h
Normal file
82
source/01_general/intl.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* file description
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* \file intl.h
|
||||||
|
* \unit intl
|
||||||
|
* \brief This is a simple large inter number calculate module for C language
|
||||||
|
* \author Lamdonn
|
||||||
|
* \version v1.0.0
|
||||||
|
* \license GPL-2.0
|
||||||
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
|
********************************************************************************************************/
|
||||||
|
#ifndef __intl_H
|
||||||
|
#define __intl_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "intl_cfg.h"
|
||||||
|
|
||||||
|
/* Version infomation */
|
||||||
|
|
||||||
|
#define INTL_V_MAJOR 1
|
||||||
|
#define INTL_V_MINOR 0
|
||||||
|
#define INTL_V_PATCH 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A structure to represent a long bits integer.
|
||||||
|
*
|
||||||
|
* This structure uses a union to store the long bits integer in two different ways:
|
||||||
|
* - An array of `INTL_U16_PARTS` uint16_t values, allowing for operations on individual 16-bit segments.
|
||||||
|
* - An array of `INTL_U32_PARTS` uint32_t values, providing a way to work with 32-bit segments.
|
||||||
|
*
|
||||||
|
* The union allows for flexibility in how the data is accessed and manipulated,
|
||||||
|
* depending on the needs of the operations being performed.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
uint16_t u16[INTL_U16_PARTS]; ///< Array of uint16_t values representing the long bit integer in 16-bit segments.
|
||||||
|
uint32_t u32[INTL_U32_PARTS]; ///< Array of uint32_t values representing the long bit integer in 32-bit segments.
|
||||||
|
};
|
||||||
|
} intl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief intl large integer api declaration, support for basic addition, subtraction, multiplication, division, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
intl intl_add(intl a, intl b);
|
||||||
|
intl intl_sub(intl a, intl b);
|
||||||
|
intl intl_mul(intl a, intl b);
|
||||||
|
intl intl_div(intl a, intl b);
|
||||||
|
intl intl_mod(intl a, intl b);
|
||||||
|
intl intl_and(intl a, intl b);
|
||||||
|
intl intl_xor(intl a, intl b);
|
||||||
|
intl intl_or(intl a, intl b);
|
||||||
|
intl intl_shl(intl a, uint32_t amount);
|
||||||
|
intl intl_shr(intl a, uint32_t amount);
|
||||||
|
intl intl_not(intl a);
|
||||||
|
intl intl_abs(intl a);
|
||||||
|
intl intl_inc(intl a);
|
||||||
|
intl intl_dec(intl a);
|
||||||
|
intl intl_neg(intl a);
|
||||||
|
intl intl_from(const char *str);
|
||||||
|
intl intl_from2(int value);
|
||||||
|
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]);
|
||||||
|
int intl_cmp(intl a, intl b);
|
||||||
|
int intl_sign(intl a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Converts a integer to an intl number.
|
||||||
|
* \param[in] value: The integer to convert.
|
||||||
|
* \return The corresponding intl number initialized with the given value.
|
||||||
|
*/
|
||||||
|
#define intl(value) intl_from2(value)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
224
source/01_general/intl_cfg.h
Normal file
224
source/01_general/intl_cfg.h
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* file description
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* \file intl_cfg.h
|
||||||
|
* \unit intl
|
||||||
|
* \brief This is a simple large int number calculate module config header file for C language
|
||||||
|
* \author Lamdonn
|
||||||
|
* \version v1.0.0
|
||||||
|
* \license GPL-2.0
|
||||||
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
|
********************************************************************************************************/
|
||||||
|
#ifndef __intl_cfg_H
|
||||||
|
#define __intl_cfg_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With this definition, you can configure the footprint size of an intl.
|
||||||
|
* This is a flexible definition that can be extended to larger numbers in addition to the given few size definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************/
|
||||||
|
/* Config start */
|
||||||
|
/*****************************************************************/
|
||||||
|
// #define INTL_USE_128BITS
|
||||||
|
// #define INTL_USE_256BITS
|
||||||
|
#define INTL_USE_512BITS
|
||||||
|
// #define INTL_USE_1024BITS
|
||||||
|
// #define INTL_USE_2048BITS
|
||||||
|
// #define INTL_USE_4096BITS
|
||||||
|
// #define INTL_USE_8192BITS
|
||||||
|
|
||||||
|
#if defined(INTL_USE_128BITS)
|
||||||
|
#define INTL_BIT_PARTS 128
|
||||||
|
#define INTL_U32_PARTS 4
|
||||||
|
#define INTL_U16_PARTS 8
|
||||||
|
#define INTL_MAX_BIN 129
|
||||||
|
#define INTL_MAX_DEC 40
|
||||||
|
#define INTL_MAX_HEX 33
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,}}
|
||||||
|
#elif defined(INTL_USE_256BITS)
|
||||||
|
#define INTL_BIT_PARTS 256
|
||||||
|
#define INTL_U32_PARTS 8
|
||||||
|
#define INTL_U16_PARTS 16
|
||||||
|
#define INTL_MAX_BIN 257
|
||||||
|
#define INTL_MAX_DEC 78
|
||||||
|
#define INTL_MAX_HEX 65
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0,0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,0,0,0,0,}}
|
||||||
|
#elif defined(INTL_USE_512BITS)
|
||||||
|
#define INTL_BIT_PARTS 512
|
||||||
|
#define INTL_U32_PARTS 16
|
||||||
|
#define INTL_U16_PARTS 32
|
||||||
|
#define INTL_MAX_BIN 513
|
||||||
|
#define INTL_MAX_DEC 155
|
||||||
|
#define INTL_MAX_HEX 129
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
|
||||||
|
#elif defined(INTL_USE_1024BITS)
|
||||||
|
#define INTL_BIT_PARTS 1024
|
||||||
|
#define INTL_U32_PARTS 32
|
||||||
|
#define INTL_U16_PARTS 64
|
||||||
|
#define INTL_MAX_BIN 1025
|
||||||
|
#define INTL_MAX_DEC 309
|
||||||
|
#define INTL_MAX_HEX 257
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
|
||||||
|
#elif defined(INTL_USE_2048BITS)
|
||||||
|
#define INTL_BIT_PARTS 2048
|
||||||
|
#define INTL_U32_PARTS 64
|
||||||
|
#define INTL_U16_PARTS 128
|
||||||
|
#define INTL_MAX_BIN 2049
|
||||||
|
#define INTL_MAX_DEC 618
|
||||||
|
#define INTL_MAX_HEX 513
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
|
||||||
|
#elif defined(INTL_USE_4096BITS)
|
||||||
|
#define INTL_BIT_PARTS 4096
|
||||||
|
#define INTL_U32_PARTS 128
|
||||||
|
#define INTL_U16_PARTS 256
|
||||||
|
#define INTL_MAX_BIN 4097
|
||||||
|
#define INTL_MAX_DEC 1234
|
||||||
|
#define INTL_MAX_HEX 1025
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
|
||||||
|
#elif defined(INTL_USE_8192BITS)
|
||||||
|
#define INTL_BIT_PARTS 8192
|
||||||
|
#define INTL_U32_PARTS 256
|
||||||
|
#define INTL_U16_PARTS 512
|
||||||
|
#define INTL_MAX_BIN 8193
|
||||||
|
#define INTL_MAX_DEC 2468
|
||||||
|
#define INTL_MAX_HEX 2049
|
||||||
|
#define INTL_MAX (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
|
||||||
|
#define INTL_MIN (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
|
||||||
|
#define INTL_ZERO (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
|
||||||
|
#endif
|
||||||
|
/*****************************************************************/
|
||||||
|
/* Config end */
|
||||||
|
/*****************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void intl_gen_cfg(uint32_t bits)
|
||||||
|
{
|
||||||
|
if ((bits & (bits - 1)) != 0)
|
||||||
|
{
|
||||||
|
printf("[ERROR] `bits` not a power of 2\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bits < 128)
|
||||||
|
{
|
||||||
|
printf("[ERROR] `bits` too small\r\b");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("/*****************************************************************/\r\n");
|
||||||
|
printf("/* Config start */\r\n");
|
||||||
|
printf("/*****************************************************************/\r\n");
|
||||||
|
|
||||||
|
for (uint32_t tb = 128; tb <= bits; tb <<= 1)
|
||||||
|
{
|
||||||
|
if (tb == bits)
|
||||||
|
{
|
||||||
|
printf("#define INTL_USE_%uBITS\r\n", tb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("// #define INTL_USE_%uBITS\r\n", tb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
|
||||||
|
intl temp;
|
||||||
|
|
||||||
|
for (uint32_t tb = 128; tb <= bits; tb <<= 1)
|
||||||
|
{
|
||||||
|
if (tb == 128)
|
||||||
|
{
|
||||||
|
printf("#if defined(INTL_USE_%uBITS)\r\n", tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("#elif defined(INTL_USE_%uBITS)\r\n", tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t BIT_PARTS ; /* bits */
|
||||||
|
uint32_t U32_PARTS ; /* INTL_BIT_PARTS / 32 */
|
||||||
|
uint32_t U16_PARTS ; /* INTL_BIT_PARTS / 16 */
|
||||||
|
uint32_t MAX_BIN ; /* INTL_BIT_PARTS + 1 */
|
||||||
|
uint32_t MAX_DEC ; /* strlen(intl_shl(intl(1), INTL_BIT_PARTS - 1)) + 1 */
|
||||||
|
uint32_t MAX_HEX ; /* INTL_BIT_PARTS / 4 + 1 */
|
||||||
|
|
||||||
|
BIT_PARTS = tb;
|
||||||
|
U32_PARTS = BIT_PARTS >> (5);
|
||||||
|
U16_PARTS = BIT_PARTS >> (4);
|
||||||
|
MAX_BIN = BIT_PARTS + 1;
|
||||||
|
MAX_DEC = MAX_BIN;
|
||||||
|
MAX_HEX = (BIT_PARTS >> (2)) + 1;
|
||||||
|
|
||||||
|
if (sizeof(temp) == (bits >> 3))
|
||||||
|
{
|
||||||
|
char buffer[INTL_MAX_BIN];
|
||||||
|
MAX_DEC = strlen(intl_sdec(intl_shl(intl(1), BIT_PARTS - 1), buffer)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("#define INTL_BIT_PARTS %u\r\n", BIT_PARTS);
|
||||||
|
printf("#define INTL_U32_PARTS %u\r\n", U32_PARTS);
|
||||||
|
printf("#define INTL_U16_PARTS %u\r\n", U16_PARTS);
|
||||||
|
printf("#define INTL_MAX_BIN %u\r\n", MAX_BIN);
|
||||||
|
printf("#define INTL_MAX_DEC %u\r\n", MAX_DEC);
|
||||||
|
printf("#define INTL_MAX_HEX %u\r\n", MAX_HEX);
|
||||||
|
intl max = (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}};
|
||||||
|
intl min = (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}};
|
||||||
|
printf("#define INTL_MAX (intl){.u32={");
|
||||||
|
for (uint32_t i = 0; i < U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
printf("%s,", (i == U32_PARTS-1) ? "0x7FFFFFFF" : "-1");
|
||||||
|
}
|
||||||
|
printf("}}\r\n");
|
||||||
|
|
||||||
|
printf("#define INTL_MIN (intl){.u32={");
|
||||||
|
for (uint32_t i = 0; i < U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
printf("%s,", (i == U32_PARTS-1) ? "0x80000000" : "0");
|
||||||
|
}
|
||||||
|
printf("}}\r\n");
|
||||||
|
|
||||||
|
printf("#define INTL_ZERO (intl){.u32={");
|
||||||
|
for (uint32_t i = 0; i < U32_PARTS; i++)
|
||||||
|
{
|
||||||
|
printf("0,");
|
||||||
|
}
|
||||||
|
printf("}}\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("#endif\r\n");
|
||||||
|
|
||||||
|
printf("/*****************************************************************/\r\n");
|
||||||
|
printf("/* Config end */\r\n");
|
||||||
|
printf("/*****************************************************************/\r\n");
|
||||||
|
|
||||||
|
printf("\r\n\r\n-------------------------------------------------------------\r\n\r\n");
|
||||||
|
|
||||||
|
if (sizeof(temp) != (bits >> 3))
|
||||||
|
{
|
||||||
|
printf("[TODO] Apply the current configuration and run it again to get the new `INTL_MAX_DEC`\r\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("[INFO] The configuration has been generated, copy it to the `intl_cfg.h` range specified\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ TEST_INC =
|
|||||||
# TEST_SRC += $(TESTSPACE)/test_map.c
|
# TEST_SRC += $(TESTSPACE)/test_map.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_heap.c
|
# TEST_SRC += $(TESTSPACE)/test_heap.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_tree.c
|
# TEST_SRC += $(TESTSPACE)/test_tree.c
|
||||||
TEST_SRC += $(TESTSPACE)/test_graph.c
|
# TEST_SRC += $(TESTSPACE)/test_graph.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_rbtree.c
|
# TEST_SRC += $(TESTSPACE)/test_rbtree.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_pthread.c
|
# TEST_SRC += $(TESTSPACE)/test_pthread.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_encrypt.c
|
# TEST_SRC += $(TESTSPACE)/test_encrypt.c
|
||||||
@ -45,5 +45,6 @@ TEST_SRC += $(TESTSPACE)/test_graph.c
|
|||||||
# TEST_SRC += $(TESTSPACE)/test_sList.c
|
# TEST_SRC += $(TESTSPACE)/test_sList.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_dList.c
|
# TEST_SRC += $(TESTSPACE)/test_dList.c
|
||||||
# TEST_SRC += $(TESTSPACE)/test_cQueue.c
|
# TEST_SRC += $(TESTSPACE)/test_cQueue.c
|
||||||
|
TEST_SRC += $(TESTSPACE)/test_intl.c
|
||||||
|
|
||||||
export TEST_SRC TEST_INC
|
export TEST_SRC TEST_INC
|
||||||
|
|||||||
105
test/test_intl.c
Normal file
105
test/test_intl.c
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "init.h"
|
||||||
|
#include "intl.h"
|
||||||
|
|
||||||
|
#define INTL_P_DEC 0x01
|
||||||
|
#define INTL_P_BIN 0x02
|
||||||
|
#define INTL_P_HEX 0x04
|
||||||
|
|
||||||
|
static void print_intl(intl a, uint8_t 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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test(void)
|
||||||
|
{
|
||||||
|
// test_define();
|
||||||
|
// test_print();
|
||||||
|
test_calculate();
|
||||||
|
}
|
||||||
|
init_export_app(test);
|
||||||
Loading…
x
Reference in New Issue
Block a user