varch/doc/floatl.md
2025-03-06 01:33:43 +08:00

6.6 KiB
Raw Blame History

介绍

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_INFFLOATL_NANFLOATL_CONST_0FLOATL_CONST_1FLOATL_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地址。 buffersize分别是存储转换结果的缓冲区的地址和大小 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