mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-08 01:36:42 +08:00
182 lines
6.6 KiB
Markdown
182 lines
6.6 KiB
Markdown
## 介绍
|
||
|
||
`floatl`为一个大型浮点数模块,该模块允许对超过 C 语言标准数据类型限制的大浮点数进行操作。它提供了一个灵活的长整型表示,使用 16 位和 32 位段来存储。
|
||
|
||
现在主流的计算机系统中一般支持的最大整形数为 32bits 或者 64bits 的,其能满足在一般情况下的计算及存储,但是面对一些更大的数时候就会显得有心无力。
|
||
而`floatl`模块作为额外的浮点数扩充,采用了与 `IEEE 754` 一致的存储机制,而且在使用起来也非常方便。提供以下的计算:
|
||
|
||
- 支持基本算术操作:加法、减法、乘法、除法。
|
||
- 将字符串和标准浮点数转换为大浮点数的功能。
|
||
- 提供以十进制、`[P-]` 和 `[E-]`格式输出大浮点数的函数。
|
||
|
||
`floatl` 可以按需配置为 64bits、128bits、256bits、512bits、1024bits、2048bits、4096bits、8192bits,如果都还不满足,还提供了生成更大bits的函数来生成更大的配置。
|
||
|
||
|
||
## 接口
|
||
|
||
## 结构定义
|
||
|
||
### `floatl`
|
||
|
||
一个结构体,用于表示长整型浮点数,使用联合体以两种不同方式存储浮点数:
|
||
|
||
- 一个 `uint16_t` 类型的数组(16 位段)。
|
||
- 一个 `uint32_t` 类型的数组(32 位段)。
|
||
|
||
```c
|
||
typedef struct {
|
||
union {
|
||
uint16_t u16[__FLOATL_U16_PARTS__]; ///< Array of uint16_t values representing the long bit integer in 16-bit segments.
|
||
uint32_t u32[__FLOATL_U32_PARTS__]; ///< Array of uint32_t values representing the long bit integer in 32-bit segments.
|
||
struct {
|
||
uint32_t mantissas[__FLOATL_MANT_PARTS__];
|
||
uint32_t mantissa : __FLOATL_MANT_HIGH_BITS__;
|
||
uint32_t exponent : __FLOATL_EXP_BITS__;
|
||
uint32_t sign : 1;
|
||
};
|
||
};
|
||
} floatl;
|
||
```
|
||
|
||
### 定义函数
|
||
|
||
```c
|
||
floatl floatl_from(const char *str);
|
||
floatl floatl_from_f(float value);
|
||
floatl floatl_from_d(double value);
|
||
```
|
||
|
||
`floatl`提供了两种定义函数。
|
||
|
||
`floatl_from`为从数字字符串中解析生成一个`floatl`,支持解析十进制、`[P-]` 和 `[E-]`格式字符串。
|
||
`floatl_from_f`为从`float`型中创建一个`floatl`。
|
||
`floatl_from_d`为从`double`型中创建一个`floatl`,此函数封装成更简短的宏定义方法`floatl()`更贴近使用习惯,此方法执行效率更高。
|
||
|
||
三者的使用,当值在`double`的取值范围内时,推荐使用`floatl()`方法,而当数值超越`double`的取值范围时或者需要不同进制进行定义时,就可以使用`floatl_from`方法。
|
||
|
||
同时,也可以使用常用值的宏定义`FLOATL_INF`、`FLOATL_NAN`、`FLOATL_CONST_0`、`FLOATL_CONST_1`、`FLOATL_CONST_10`等。
|
||
|
||
例子:
|
||
```c
|
||
static void test_define(void)
|
||
{
|
||
floatl a = floatl(0.0);
|
||
floatl b = floatl(10.0);
|
||
floatl c = floatl(-3.14);
|
||
floatl d = floatl(1.23456789e+10);
|
||
floatl e = floatl(0x1.23456789p+10);
|
||
|
||
floatl f = floatl_from("0.0");
|
||
floatl g = floatl_from("10.0");
|
||
floatl h = floatl_from("-3.14");
|
||
floatl i = floatl_from("1.23456789e+10");
|
||
floatl j = floatl_from("0x1.23456789p+10");
|
||
|
||
floatl zero = FLOATL_CONST_0;
|
||
floatl one = FLOATL_CONST_1;
|
||
floatl ten = FLOATL_CONST_10;
|
||
|
||
printf("size %d\r\n", sizeof(floatl));
|
||
}
|
||
```
|
||
|
||
### 转换函数
|
||
|
||
```c
|
||
int floatl_print(floatl a, char *buffer, uint32_t size, const char *format);
|
||
#define floatl_show(a, b, s, f) (floatl_print((a), (b), (s), (f)) > 0 ? (b) : "invalid")
|
||
```
|
||
|
||
此函数把`a`的值根据格式转换成十进制、`[P-]` 和 `[E-]`格式到传入的`buffer`中,并返回有效位的`buffer`地址。
|
||
`buffer`和`size`分别是存储转换结果的缓冲区的地址和大小
|
||
`format`使用与`printf`类似,```[flags][width][type]```,如`0.2f`、`+5.2a`等。
|
||
|
||
```c
|
||
static void test_print(void)
|
||
{
|
||
floatl a = floatl_from("1234567890.123456789");
|
||
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%f"));
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%.2f"));
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%020.2f"));
|
||
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%+.6a"));
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%+20.6a"));
|
||
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%-20.6e"));
|
||
}
|
||
```
|
||
|
||
结果:
|
||
```
|
||
a 1234567890.123451
|
||
a 1234567890.12
|
||
a 00000001234567890.12
|
||
a +0x1.26580bp+30
|
||
a +0x1.26580bp+30
|
||
a 1.234568e+009
|
||
```
|
||
|
||
### 运算函数
|
||
|
||
```c
|
||
floatl floatl_add(floatl a, floatl b); // a+b
|
||
floatl floatl_sub(floatl a, floatl b); // a-b
|
||
floatl floatl_mul(floatl a, floatl b); // a*b
|
||
floatl floatl_div(floatl a, floatl b); // a/b
|
||
floatl floatl_abs(floatl a); // |a|
|
||
floatl floatl_neg(floatl a); // -a
|
||
int floatl_eq(floatl a, floatl b); // a<b
|
||
int floatl_ne(floatl a, floatl b); // a<=b
|
||
int floatl_lt(floatl a, floatl b); // a==b
|
||
int floatl_le(floatl a, floatl b); // a!=b
|
||
int floatl_gt(floatl a, floatl b); // a>b
|
||
int floatl_ge(floatl a, floatl b); // a>=b
|
||
```
|
||
|
||
`floatl`运算函数与类似符号运算一致。
|
||
|
||
使用例子:
|
||
```c
|
||
static void test_calculate(void)
|
||
{
|
||
floatl a = floatl_from("12345678901234567890.123456789");
|
||
floatl b = floatl_from("98765432109876543210.987654321");
|
||
|
||
printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%f"));
|
||
printf("b %s\r\n", floatl_show(b, buffer, sizeof(buffer), "%f"));
|
||
|
||
printf("a + b: %s\r\n", floatl_show(floatl_add(a, b), buffer, sizeof(buffer), "%f"));
|
||
printf("a - b: %s\r\n", floatl_show(floatl_sub(a, b), buffer, sizeof(buffer), "%f"));
|
||
printf("a * b: %s\r\n", floatl_show(floatl_mul(a, b), buffer, sizeof(buffer), "%f"));
|
||
printf("a / b: %s\r\n", floatl_show(floatl_div(a, b), buffer, sizeof(buffer), "%f"));
|
||
printf("-a: %s\r\n", floatl_show(floatl_neg(a), buffer, sizeof(buffer), "%f"));
|
||
printf("|a|: %s\r\n", floatl_show(floatl_abs(a), buffer, sizeof(buffer), "%f"));
|
||
printf("a > b: %d\r\n", floatl_gt(a, b));
|
||
printf("a >= b: %d\r\n", floatl_ge(a, b));
|
||
printf("a < b: %d\r\n", floatl_lt(a, b));
|
||
printf("a <= b: %d\r\n", floatl_le(a, b));
|
||
printf("a == b: %d\r\n", floatl_eq(a, b));
|
||
printf("a != b: %d\r\n", floatl_ne(a, b));
|
||
}
|
||
```
|
||
|
||
结果:
|
||
```
|
||
a 12345678901234567890.123457
|
||
b 98765432109876543210.987654
|
||
a + b: 111111111011111111101.111111
|
||
a - b: -86419753208641975320.864198
|
||
a * b: 1219326311370217952261850327336229233322.374638
|
||
a / b: 0.125000
|
||
-a: -12345678901234567890.123457
|
||
|a|: 12345678901234567890.123457
|
||
a > b: 0
|
||
a >= b: 0
|
||
a < b: 1
|
||
a <= b: 1
|
||
a == b: 0
|
||
a != b: 1
|
||
```
|
||
|