6.6 KiB
介绍
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 位段)。
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;
定义函数
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等。
例子:
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));
}
转换函数
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等。
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
运算函数
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运算函数与类似符号运算一致。
使用例子:
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