From fa4bd85f2ed3ad80448442b5dc33c71feaebe2ad Mon Sep 17 00:00:00 2001 From: Lamdonn Date: Tue, 4 Mar 2025 11:15:49 +0800 Subject: [PATCH] 1. Add math category folder 2. Add the floatl initial version 3. Add the intl_print function 4. Fix intl_from issue 5. Add intl unit test code --- README.en.md | 6 +- README.md | 6 +- doc/floatl.en.md | 181 ++ doc/floatl.md | 181 ++ makefile | 3 + release.txt | 12 + source/01_general/intl.h | 82 - source/01_general/intl_cfg.h | 224 -- source/07_math/floatl.c | 3783 +++++++++++++++++++++++++ source/07_math/floatl.h | 174 ++ source/07_math/floatl_cfg.h | 779 +++++ source/{01_general => 07_math}/intl.c | 633 +++-- source/07_math/intl.h | 113 + source/07_math/intl_cfg.h | 263 ++ test/test.mk | 3 +- test/test_floatl.c | 1470 ++++++++++ test/test_intl.c | 382 ++- 17 files changed, 7642 insertions(+), 653 deletions(-) create mode 100644 doc/floatl.en.md create mode 100644 doc/floatl.md delete mode 100644 source/01_general/intl.h delete mode 100644 source/01_general/intl_cfg.h create mode 100644 source/07_math/floatl.c create mode 100644 source/07_math/floatl.h create mode 100644 source/07_math/floatl_cfg.h rename source/{01_general => 07_math}/intl.c (60%) create mode 100644 source/07_math/intl.h create mode 100644 source/07_math/intl_cfg.h create mode 100644 test/test_floatl.c diff --git a/README.en.md b/README.en.md index 009209e..e5275b6 100644 --- a/README.en.md +++ b/README.en.md @@ -2,7 +2,7 @@ ![logo](/image/logo.png) -[![Version](https://img.shields.io/badge/version-0.2.0-blue.svg)](https://gitee.com/Lamdonn/varch) +[![Version](https://img.shields.io/badge/version-0.3.1-blue.svg)](https://gitee.com/Lamdonn/varch) [![License](https://img.shields.io/badge/license-GPL%202.0-brightgreen.svg)](LICENSE) [![Author](https://img.shields.io/badge/author-Lamdonn%20%20%20%20%20-brightblue.svg)](Lamdonn@163.com) ![Supported Platforms](https://img.shields.io/badge/platform-Linux%20&%20MinGW-yellow.svg) @@ -18,7 +18,7 @@ It has the characteristics of **simplicity, universality, and efficiency**, with | module | version | usage | path | describe | |:-------------|:---------|:-----------------------------|:------------------------------------------|:--------------------------------------| -| overall | 00.03.00 | [link](README.en.md) | [path](./) | Overall +| overall | 00.03.01 | [link](README.en.md) | [path](./) | Overall | init | 01.00.00 | [link](/doc/init.en.md) | [path](./source/00_application) | Initialize export module | console | 01.00.01 | [link](/doc/console.en.md) | [path](./source/00_application/console) | Console command input, combined with the 'command' module, parsing commands entered in the console | arg | 01.00.00 | [link](/doc/arg.en.md) | [path](./source/01_general) | Indefinite parameters, obtain the number of indefinite parameters and specified parameters @@ -72,6 +72,8 @@ It has the characteristics of **simplicity, universality, and efficiency**, with | romt | 01.00.00 | [link](/doc/romt.en.md) | [path](./source/06_performance) | ROM test module | cpul | 01.00.00 | [link](/doc/cpul.en.md) | [path](./source/06_performance) | CPU load test module, including obtaining and increasing load | unitt | 01.00.00 | [link](/doc/unitt.en.md) | [path](./source/06_performance) | Simple unit test module +| intl | 01.00.00 | [link](/doc/intl.en.md) | [path](./source/07_math) | Large integer arithmetic module +| floatl | 01.00.00 | [link](/doc/floatl.en.md) | [path](./source/07_math) | Large floating-point arithmetic module ## Usage diff --git a/README.md b/README.md index 406add0..ad83f50 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![logo](/image/logo.png) -[![Version](https://img.shields.io/badge/version-0.2.0-blue.svg)](https://gitee.com/Lamdonn/varch) +[![Version](https://img.shields.io/badge/version-0.3.1-blue.svg)](https://gitee.com/Lamdonn/varch) [![License](https://img.shields.io/badge/license-GPL%202.0-brightgreen.svg)](LICENSE) [![Author](https://img.shields.io/badge/author-Lamdonn%20%20%20%20%20-brightblue.svg)](Lamdonn@163.com) ![Supported Platforms](https://img.shields.io/badge/platform-Linux%20&%20MinGW-yellow.svg) @@ -18,7 +18,7 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用 | module | version | usage | path | describe | |:-------------|:---------|:-----------------------------|:------------------------------------------|:--------------------------------------| -| overall | 00.03.00 | [link](README.md) | [path](./) | 整体 +| overall | 00.03.01 | [link](README.md) | [path](./) | 整体 | init | 01.00.00 | [link](/doc/init.md) | [path](./source/00_application) | 初始化导出模块 | console | 01.00.01 | [link](/doc/console.md) | [path](./source/00_application/console) | 控制台命令输入,结合 `command` 模块,解析在控制台中输入的命令 | arg | 01.00.00 | [link](/doc/arg.md) | [path](./source/01_general) | 不定参数,获取不定参数和指定参数的个数 @@ -72,6 +72,8 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用 | romt | 01.00.00 | [link](/doc/romt.md) | [path](./source/06_performance) | ROM测试模块 | cpul | 01.00.00 | [link](/doc/cpul.md) | [path](./source/06_performance) | CPU负载测试模块,包含获取和增加负载 | unitt | 01.00.00 | [link](/doc/unitt.md) | [path](./source/06_performance) | 简易的单元测试模块 +| intl | 01.00.00 | [link](/doc/intl.md) | [path](./source/07_math) | 大型整数运算模块 +| floatl | 01.00.00 | [link](/doc/floatl.md) | [path](./source/07_math) | 大型浮点数运算模块 ## 使用说明 diff --git a/doc/floatl.en.md b/doc/floatl.en.md new file mode 100644 index 0000000..3b7a6b2 --- /dev/null +++ b/doc/floatl.en.md @@ -0,0 +1,181 @@ +## Introduction + +`floatl` is a large floating-point number module that allows operations on large floating-point numbers exceeding the limits of standard C language data types. It provides a flexible long-integer representation, using 16-bit and 32-bit segments for storage. + +In current mainstream computer systems, the maximum integer types generally supported are 32-bit or 64-bit integers, which can meet the computational and storage requirements in general cases. However, they become inadequate when dealing with larger numbers. + +As an additional extension for floating-point numbers, the `floatl` module adopts a storage mechanism consistent with `IEEE 754` and is very convenient to use. It supports the following calculations: + +- Basic arithmetic operations: addition, subtraction, multiplication, and division. +- Functions to convert strings and standard floating-point numbers to large floating-point numbers. +- Functions to output large floating-point numbers in decimal, `[P-]`, and `[E-]` formats. + +`floatl` can be configured as 64-bit, 128-bit, 256-bit, 512-bit, 1024-bit, 2048-bit, 4096-bit, or 8192-bit as needed. If these configurations are still insufficient, it also provides functions to generate larger bit configurations. + +## Interfaces + +### Structure Definitions + +#### `floatl` + +A structure used to represent long-integer floating-point numbers, using a union to store floating-point numbers in two different ways: + +- An array of `uint16_t` type (16-bit segments). +- An array of `uint32_t` type (32-bit segments). + +```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; +``` + +### Definition Functions + +```c +floatl floatl_from(const char *str); +floatl floatl_from_f(float value); +floatl floatl_from_d(double value); +``` + +`floatl` provides two types of definition functions. + +`floatl_from` parses a `floatl` from a numeric string and supports parsing strings in decimal, `[P-]`, and `[E-]` formats. +`floatl_from_f` creates a `floatl` from a `float` type. +`floatl_from_d` creates a `floatl` from a `double` type. This function is encapsulated into a shorter macro definition `floatl()`, which is more in line with usage habits and has higher execution efficiency. + +When using these three functions, if the value is within the range of `double`, it is recommended to use the `floatl()` method. When the value exceeds the range of `double` or when different number systems are required for definition, the `floatl_from` method can be used. + +Meanwhile, you can also use the macro definitions of common values such as `FLOATL_INF`, `FLOATL_NAN`, `FLOATL_CONST_0`, `FLOATL_CONST_1`, `FLOATL_CONST_10`, etc. + +Example: +```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)); +} +``` + +### Conversion Functions + +```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") +``` + +This function converts the value of `a` into decimal, `[P-]`, and `[E-]` formats according to the specified format and stores the result in the passed `buffer`. It then returns the address of the valid part of the `buffer`. +`buffer` and `size` are the address and size of the buffer used to store the conversion result, respectively. +`format` is similar to that used in `printf`, with the format ```[flags][width][type]```, such as `0.2f`, `+5.2a`, etc. + +```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")); +} +``` + +Results: +``` +a 1234567890.123451 +a 1234567890.12 +a 00000001234567890.12 +a +0x1.26580bp+30 +a +0x1.26580bp+30 +a 1.234568e+009 +``` + +### Arithmetic Functions + +```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); // ab +int floatl_ge(floatl a, floatl b); // a>=b +``` + +The arithmetic functions of `floatl` are consistent with the corresponding symbolic operations. + +Usage example: +```c +static void test_calculate(void) +{ + floatl a = floatl_from("123456789.123456789"); + floatl b = floatl_from("987654321.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("b / a: %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)); +} +``` + +Results: +``` +a 123456789.123456 +b 987654321.987650 +a + b: 1111111111.111118 +a - b: -864197532.864200 +a * b: 121932631356500755.185485 +b / a: 0.125000 +-a: -123456789.123456 +|a|: 123456789.123456 +a > b: 0 +a >= b: 0 +a < b: 1 +a <= b: 1 +a == b: 0 +a != b: 1 +``` + diff --git a/doc/floatl.md b/doc/floatl.md new file mode 100644 index 0000000..21f5e23 --- /dev/null +++ b/doc/floatl.md @@ -0,0 +1,181 @@ +## 介绍 + +`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); // ab +int floatl_ge(floatl a, floatl b); // a>=b +``` + +`floatl`运算函数与类似符号运算一致。 + +使用例子: +```c +static void test_calculate(void) +{ + floatl a = floatl_from("123456789.123456789"); + floatl b = floatl_from("987654321.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("b / a: %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 123456789.123456 +b 987654321.987650 +a + b: 1111111111.111118 +a - b: -864197532.864200 +a * b: 121932631356500755.185485 +b / a: 0.125000 +-a: -123456789.123456 +|a|: 123456789.123456 +a > b: 0 +a >= b: 0 +a < b: 1 +a <= b: 1 +a == b: 0 +a != b: 1 +``` + diff --git a/makefile b/makefile index ef6a937..f2fa3a0 100644 --- a/makefile +++ b/makefile @@ -20,6 +20,7 @@ CONTAINER_PATH = $(WORKSPACE)/03_container ALGORITHM_PATH = $(WORKSPACE)/04_algorithm PARSER_PATH = $(WORKSPACE)/05_parser PERFORMANCE_PATH = $(WORKSPACE)/06_performance +MATH_PATH = $(WORKSPACE)/07_math ################################################################################## ### sources, libaries and head path @@ -31,6 +32,7 @@ INCLUDE += $(CONTAINER_PATH) INCLUDE += $(ALGORITHM_PATH) INCLUDE += $(PARSER_PATH) INCLUDE += $(PERFORMANCE_PATH) +INCLUDE += $(MATH_PATH) LIBSRCS += $(APPLICATION_PATH)/init.c LIBSRCS += $(wildcard $(APPLICATION_PATH)/console/*.c) @@ -40,6 +42,7 @@ LIBSRCS += $(wildcard $(CONTAINER_PATH)/*.c) LIBSRCS += $(wildcard $(ALGORITHM_PATH)/*.c) LIBSRCS += $(wildcard $(PARSER_PATH)/*.c) LIBSRCS += $(wildcard $(PERFORMANCE_PATH)/*.c) +LIBSRCS += $(wildcard $(MATH_PATH)/*.c) LIBLIST += m LIBLIST += pthread diff --git a/release.txt b/release.txt index 3a98d5e..6760ffb 100644 --- a/release.txt +++ b/release.txt @@ -1,3 +1,15 @@ +version 0.3.1 +date 2025.03.04 +changes + 1. Add math category folder + 2. Add the floatl initial version + 3. Add the intl_print function + 4. Fix intl_from issue + 5. Add intl unit test code + +--------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------- + version 0.3.0 date 2024.12.18 changes diff --git a/source/01_general/intl.h b/source/01_general/intl.h deleted file mode 100644 index 514f33e..0000000 --- a/source/01_general/intl.h +++ /dev/null @@ -1,82 +0,0 @@ - -/********************************************************************************************************* - * ------------------------------------------------------------------------------------------------------ - * 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 -#include -#include -#include -#include -#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 - diff --git a/source/01_general/intl_cfg.h b/source/01_general/intl_cfg.h deleted file mode 100644 index 4c527fb..0000000 --- a/source/01_general/intl_cfg.h +++ /dev/null @@ -1,224 +0,0 @@ - -/********************************************************************************************************* - * ------------------------------------------------------------------------------------------------------ - * 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 - diff --git a/source/07_math/floatl.c b/source/07_math/floatl.c new file mode 100644 index 0000000..a1678e6 --- /dev/null +++ b/source/07_math/floatl.c @@ -0,0 +1,3783 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file floatl.c + * \unit floatl + * \brief This is a simple large float number calculate module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#include "floatl.h" + +/** + * \brief A union for representing a single - precision floating - point number in different forms. + * + * This union allows accessing a single - precision floating - point number (float) in three different ways: + * 1. As a standard 'float' type. + * 2. As an unsigned 32 - bit integer. + * 3. As a structured representation with separate fields for the sign, exponent, and mantissa. + */ +typedef union { + // Access the value as a standard single - precision floating - point number + float float_; + // Access the binary representation of the floating - point number as an unsigned 32 - bit integer + uint32_t int_; + // Access the individual components of the floating - point number (sign, exponent, mantissa) + struct + { + // The mantissa of the floating - point number, occupying 23 bits + uint32_t mantissa : 23; + // The exponent of the floating - point number, occupying 8 bits + uint32_t exponent : 8; + // The sign of the floating - point number, occupying 1 bit (0 for positive, 1 for negative) + uint32_t sign : 1; + }; +} float_u; + +/** + * \brief A union for representing a double - precision floating - point number in different forms. + * + * This union allows accessing a double - precision floating - point number (double) in three different ways: + * 1. As a standard 'double' type. + * 2. As a structure containing two 32 - bit unsigned integers (low and high parts). + * 3. As a structured representation with separate fields for the sign, exponent, and mantissa. + */ +typedef union { + // Access the value as a standard double - precision floating - point number + double float_; + // Access the binary representation of the floating - point number as two 32 - bit unsigned integers + struct + { + // The lower 32 bits of the binary representation + uint32_t low; + // The upper 32 bits of the binary representation + uint32_t high; + } int_; + // Access the individual components of the floating - point number (sign, exponent, mantissa) + struct + { + // The lower part of the mantissa of the floating - point number + uint32_t mantissa_l; + // The upper 20 bits of the mantissa of the floating - point number + uint32_t mantissa_h : 20; + // The exponent of the floating - point number, occupying 11 bits + uint32_t exponent : 11; + // The sign of the floating - point number, occupying 1 bit (0 for positive, 1 for negative) + uint32_t sign : 1; + }; +} double_u; + +/** + * \brief Definition of the 'floatl2' structure. + * + * This structure is designed to represent a long - bit floating - point number in multiple ways. + * It uses a union to provide different views of the same underlying data, + * which can be accessed as arrays of 16 - bit or 32 - bit unsigned integers, + * or as a combination of two 'floatl' structures. + */ +typedef struct { + /** + * \brief Union to provide different representations of the underlying data. + * + * The union allows the data to be accessed in various formats: + * as an array of 16 - bit unsigned integers, an array of 32 - bit unsigned integers, + * or as two 'floatl' structures representing low and high parts. + */ + union { + /** + * \brief Array of uint16_t values representing the long bit integer in 16 - bit segments. + * + * This array can be used to access the underlying data in 16 - bit chunks. + * The size of the array is determined by the macro __FLOATL2_U16_PARTS__. + */ + uint16_t u16[__FLOATL2_U16_PARTS__]; + + /** + * \brief Array of uint32_t values representing the long bit integer in 32 - bit segments. + * + * This array can be used to access the underlying data in 32 - bit chunks. + * The size of the array is determined by the macro __FLOATL2_U32_PARTS__. + */ + uint32_t u32[__FLOATL2_U32_PARTS__]; + + /** + * \brief Structured view with low and high 'floatl' components. + * + * This struct divides the long - bit floating - point number into a low - order and a high - order 'floatl' part. + */ + struct { + /** + * \brief The low - order 'floatl' part of the long - bit floating - point number. + */ + floatl low; + + /** + * \brief The high - order 'floatl' part of the long - bit floating - point number. + */ + floatl high; + }; + }; +} floatl2; + +/** + * \brief Definition of the FL_STACK structure. + * + * This structure represents a stack data structure. It contains information + * about the stack's base address, capacity, current size, and the index of the stack tail. + */ +typedef struct +{ + /** + * \brief Protected: base address of data. + * + * This pointer points to the base address of the memory area where the stack data is stored. + */ + char* base; + + /** + * \brief Protected: capacity of stack. + * + * It indicates the maximum number of elements that the stack can hold. + */ + int capacity; + + /** + * \brief Protected: size of stack. + * + * This variable stores the current number of elements in the stack. + */ + int size; + + /** + * \brief Protected: index of stack tail. + * + * It represents the index where the next element will be pushed or the last element was popped. + */ + int tail; +} FL_STACK; + +/** + * \brief Macro to create a 'floatl2' structure with a given low - order part and a zero high - order part. + * \param x: The value to be assigned to the 'low' member of the 'floatl2' structure. + * \return A 'floatl2' structure with the 'low' member set to 'x' and the 'high' member set to '__FLOATL_INT_ZERO__'. + * + * This macro simplifies the creation of a 'floatl2' structure by providing a convenient way to initialize + * the 'low' member while setting the 'high' member to a predefined zero value. + */ +#define FLOATL2(x) (floatl2){.low=(x),.high=__FLOATL_INT_ZERO__} + +/** + * \brief Flag indicating zero - padding for formatted output. + * + * When this flag is set, the output will be padded with zeros instead of spaces when the width is specified. + */ +#define FLAGS_ZEROPAD (0x01) + +/** + * \brief Flag indicating left - alignment for formatted output. + * + * When this flag is set, the output will be left - aligned within the specified width. + */ +#define FLAGS_LEFT (0x02) + +/** + * \brief Flag indicating that a plus sign should be prepended to positive numbers in formatted output. + * + * When this flag is set, positive numbers will be prefixed with a '+' sign. + */ +#define FLAGS_PLUS (0x04) + +/** + * \brief Flag indicating that a space should be prepended to positive numbers in formatted output. + * + * When this flag is set, positive numbers will be prefixed with a space. + */ +#define FLAGS_SPACE (0x08) + +/** + * \brief Flag indicating the use of an alternate form for formatted output. + * + * The exact meaning of the alternate form depends on the specific format specifier. + */ +#define FLAGS_HASH (0x10) + +/** + * \brief Flag indicating uppercase output for certain format specifiers. + * + * When this flag is set, format specifiers that support case (e.g., 'a' vs 'A') will use the uppercase form. + */ +#define FLAGS_CASE (0x20) + +/** + * \brief Macro to print a character to the output buffer. + * \param c: The character to be printed. + * + * This macro checks if there is enough space in the buffer to store the character. + * If there is, it adds the character to the buffer and increments the length. + * If not, it returns - 2 to indicate that the buffer is too small. + */ +#define PRINT_CHAR(c) do { if (length < max) { buffer[length++] = (c); } else return -2; } while (0) + +/** + * \brief An array storing powers of 10 from 10^0 to 10^15 in 'floatl' format. + * + * Each element in this array represents a power of 10, where the index corresponds to the exponent. + * For example, flpow10[0] is 10^0, flpow10[1] is 10^1, and so on up to flpow10[15] which is 10^15. + */ +static floatl flpow10[16] = { + FLOATL_CONST_1e0 , ///< Represents 10^0 + FLOATL_CONST_1e1 , ///< Represents 10^1 + FLOATL_CONST_1e2 , ///< Represents 10^2 + FLOATL_CONST_1e3 , ///< Represents 10^3 + FLOATL_CONST_1e4 , ///< Represents 10^4 + FLOATL_CONST_1e5 , ///< Represents 10^5 + FLOATL_CONST_1e6 , ///< Represents 10^6 + FLOATL_CONST_1e7 , ///< Represents 10^7 + FLOATL_CONST_1e8 , ///< Represents 10^8 + FLOATL_CONST_1e9 , ///< Represents 10^9 + FLOATL_CONST_1e10, ///< Represents 10^10 + FLOATL_CONST_1e11, ///< Represents 10^11 + FLOATL_CONST_1e12, ///< Represents 10^12 + FLOATL_CONST_1e13, ///< Represents 10^13 + FLOATL_CONST_1e14, ///< Represents 10^14 + FLOATL_CONST_1e15, ///< Represents 10^15 +}; + +/* Internal static function declarations */ + +static int count_u32_leading_zero(uint32_t x); +static floatl floatl_pow10(int32_t n); +static char hexI(char c); +static int pad_mant(floatl *number, int *part, int *bitoffset, int *bitnum, char c); + +static int floatl_int_ucmp(floatl a, floatl b); +static floatl floatl_int_umul(floatl a, floatl b); +static floatl floatl_int_udiv(floatl a, floatl b, floatl *mod); +static floatl floatl_int_umod(floatl a, floatl b); +static floatl floatl_int_add(floatl a, floatl b); +static floatl floatl_int_sub(floatl a, floatl b); +static floatl floatl_int_inc(floatl a); +static floatl floatl_int_dec(floatl a); +static floatl floatl_int_mul(floatl a, floatl b); +static floatl floatl_int_div(floatl a, floatl b); +static floatl floatl_int_mod(floatl a, floatl b); +static floatl floatl_int_shl(floatl a, uint32_t amount); +static floatl floatl_int_shr(floatl a, uint32_t amount); +static floatl floatl_int_and(floatl a, floatl b); +static floatl floatl_int_or(floatl a, floatl b); +static floatl floatl_int_xor(floatl a, floatl b); +static floatl floatl_int_not(floatl a); +static floatl floatl_int_abs(floatl a); +static int floatl_int_sign(floatl a); +static int floatl_int_cmp(floatl a, floatl b); +static floatl floatl_int_neg(floatl a); + +static int floatl2_int_ucmp(floatl2 a, floatl2 b); +static floatl2 floatl2_int_shr(floatl2 a, uint32_t amount); +static floatl2 floatl2_int_shl(floatl2 a, uint32_t amount); +static int floatl2_int_sign(floatl2 a); +static floatl2 floatl2_int_add(floatl2 a, floatl2 b); +static floatl2 floatl2_int_sub(floatl2 a, floatl2 b); +static floatl2 floatl2_int_umul(floatl2 a, floatl2 b); +static floatl2 floatl2_int_udiv(floatl2 a, floatl2 b, floatl2 *mod); + +/** + * \brief Push a character onto the stack. + * \param[in,out] st: Pointer to the FL_STACK structure. + * \param[in] c: The character to be pushed onto the stack. + * \return 1 if the push operation is successful, always returns 1 in this implementation. + * + * This function adds a character to the stack. If the stack is not full, it increments the size. + * It then updates the tail index in a circular manner. + */ +static int fl_stack_push(FL_STACK *st, char c) +{ + // Store the character at the current tail position + st->base[st->tail] = c; + // If the stack is not full, increment the size + if (st->size < st->capacity) st->size++; + // Update the tail index in a circular manner + st->tail = (st->tail + 1) % st->capacity; + return 1; +} + +/** + * \brief Pop a character from the stack. + * \param[in,out] st: Pointer to the FL_STACK structure. + * \param[out] c: Pointer to a character where the popped value will be stored. + * \return 1 if the pop operation is successful, 0 if the stack is empty. + * + * This function removes a character from the stack. It first checks if the stack is empty. + * If not, it updates the tail index in a circular manner, retrieves the character, and decrements the size. + */ +static int fl_stack_pop(FL_STACK *st, char *c) +{ + // Check if the stack is empty + if (st->size == 0) return 0; + // Update the tail index in a circular manner to point to the last element + st->tail = (st->tail + st->capacity - 1) % st->capacity; + // Retrieve the character at the updated tail position + *c = st->base[st->tail]; + // Decrement the size of the stack + st->size--; + return 1; +} + +/** + * \brief Push a character onto the stack from the head (a special push operation). + * \param[in,out] st: Pointer to the FL_STACK structure. + * \param[in] c: The character to be pushed onto the stack. + * \return 1 if the push operation is successful, 0 if the stack is full. + * + * This function adds a character to the stack from the "head" position. + * It first checks if the stack is full. If not, it calculates the appropriate position + * to insert the character and then increments the size. + */ +static int fl_stack_push_h(FL_STACK *st, char c) +{ + // Check if the stack is full + if (st->size == st->capacity) return 0; + // Calculate the position to insert the character from the head + st->base[(st->tail - st->size + st->capacity - 1) % st->capacity] = c; + // Increment the size of the stack + st->size++; + return 1; +} + +/** + * \brief Adds two floatl numbers. + * + * This function computes the sum of two 128-bit integers + * (floatl). It processes each 16-bit part of the input integers, + * handling carry bits as necessary. The result is stored in a + * new floatl number. This function ensures that overflow is + * correctly managed across all parts. + * + * \param[in] a: The first operand (floatl number). + * \param[in] b: The second operand (floatl number). + * \return The sum of a and b as an floatl (128-bit integer). + */ +static floatl floatl_int_add(floatl a, floatl b) +{ + floatl result; // Initialize the result variable + uint16_t carry = 0; /** Carry bit */ + + // Perform addition for each 16-bit part + for (int i = 0; i < __FLOATL_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 floatl number +} + +/** + * \brief Subtracts one floatl number from another. + * + * This function computes the difference of two 128-bit integers + * (floatl). It processes each 16-bit part of the minuend and + * subtrahend, handling borrow bits as necessary. The result is + * stored in a new floatl 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 floatl (128-bit integer). + */ +static floatl floatl_int_sub(floatl a, floatl b) +{ + floatl result; // Initialize the result variable + + // Perform subtraction for each 16-bit part + for (int i = 0; i < __FLOATL_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 < __FLOATL_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 floatl number +} + +/** + * \brief Increments the floatl number by one. + * + * This function increments a 128-bit integer (floatl) 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 floatl number to increment. + * \return The incremented floatl number as an floatl (128-bit integer). + */ +static floatl floatl_int_inc(floatl a) +{ + // Increment each 32-bit part of the floatl number + for (int i = 0; i < __FLOATL_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 floatl number by one. + * + * This function decrements a 128-bit integer (floatl) 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 floatl number to decrement. + * \return The decremented floatl number as an floatl (128-bit integer). + */ +static floatl floatl_int_dec(floatl a) +{ + // Decrement each 32-bit part of the floatl number + for (int i = 0; i < __FLOATL_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 floatl unsigned numbers. + * + * This function performs multiplication of two 128-bit unsigned integers + * (floatl) 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 floatl (128-bit unsigned integer). + */ +static floatl floatl_int_umul(floatl a, floatl b) +{ + floatl result = {0}; /** Initialize the result to 0 */ + floatl temp[__FLOATL_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 < __FLOATL_U16_PARTS__; i++) + { + carry = 0; // Reset carry for the current row + for (int j = 0; j < __FLOATL_U16_PARTS__; j++) + { + if (i + j < __FLOATL_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 < __FLOATL_U16_PARTS__; i++) + { + uint32_t add = 0; // Variable to hold the sum of the current column + for (int j = 0; j < __FLOATL_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 floatl numbers. + * + * This function multiplies two 128-bit integers (floatl) and returns + * the product as another floatl 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 `floatl_int_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 floatl (128-bit integer). + */ +static floatl floatl_int_mul(floatl a, floatl b) +{ + floatl 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[__FLOATL_U32_PARTS__ - 1] & 0x80000000) + { + sign = -sign; // Negate the sign for the result + a = floatl_int_neg(a); // Negate the first operand + } + + // Check and handle the sign of the second operand + if (b.u32[__FLOATL_U32_PARTS__ - 1] & 0x80000000) + { + sign = -sign; // Negate the sign for the result + b = floatl_int_neg(b); // Negate the second operand + } + + // Perform unsigned multiplication + result = floatl_int_umul(a, b); + + // If the result should be negative, negate it + if (sign < 0) + result = floatl_int_neg(result); + + return result; // Return the final product +} + +/** + * \brief Divides one floatl unsigned number by another. + * + * This function performs division of one 128-bit unsigned integer (floatl) + * 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 floatl (128-bit unsigned integer). + */ +static floatl floatl_int_udiv(floatl a, floatl b, floatl *mod) +{ + // Check for division by zero + if (floatl_int_sign(b) == 0) + { + printf("Division by zero!\n"); + return (floatl){0}; /** Handle division by zero */ + } + + floatl result = {0}; // Initialize the result to zero + floatl remainder = {0}; // Initialize the remainder to zero + + /** Calculate bit by bit from the highest bit */ + for (int i = __FLOATL_BIT_PARTS__ - 1; i >= 0; i--) + { + /** Left shift remainder and add current bit */ + remainder = floatl_int_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 (floatl_int_ucmp(remainder, b) >= 0) + { + remainder = floatl_int_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 floatl number by another. + * + * This function performs division of two 128-bit integers (floatl) + * and returns the quotient as another floatl 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 + * `floatl_int_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 floatl (128-bit integer). + */ +static floatl floatl_int_div(floatl a, floatl b) +{ + floatl 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[__FLOATL_U32_PARTS__ - 1] & 0x80000000) + { + sign = -sign; // Negate the sign for the result + a = floatl_int_neg(a); // Negate the dividend + } + + // Check and handle the sign of the divisor + if (b.u32[__FLOATL_U32_PARTS__ - 1] & 0x80000000) + { + sign = -sign; // Negate the sign for the result + b = floatl_int_neg(b); // Negate the divisor + } + + // Perform unsigned division + result = floatl_int_udiv(a, b, NULL); + + // If the result should be negative, negate it + if (sign < 0) + result = floatl_int_neg(result); + + return result; // Return the final quotient +} + +/** + * \brief Computes the remainder of the division of two unsigned floatl numbers. + * + * This function calculates the remainder of the division of two + * 128-bit unsigned integers (floatl). 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 floatl (128-bit unsigned integer). + */ +static floatl floatl_int_umod(floatl a, floatl b) +{ + floatl mod = {0}; + floatl_int_udiv(a, b, &mod); + return mod; +} + +/** + * \brief Computes the remainder of the division of two floatl numbers. + * + * This function calculates the remainder of the division of two + * 128-bit integers (floatl). 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 + * `floatl_int_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 floatl (128-bit integer). + */ +static floatl floatl_int_mod(floatl a, floatl b) +{ + floatl 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[__FLOATL_U32_PARTS__ - 1] & 0x80000000) + { + sign = -sign; // Negate the sign for the result + a = floatl_int_neg(a); // Negate the dividend + } + + // Perform unsigned modulus with the absolute value of the divisor + result = floatl_int_umod(a, floatl_int_abs(b)); + + // If the result should be negative, negate it + if (sign < 0) + result = floatl_int_neg(result); + + return result; // Return the final remainder +} + +/** + * \brief Left shifts an floatl number by a specified number of bits. + * + * This function performs a left bitwise shift on a 128-bit integer + * (floatl). 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 floatl number to shift. + * \param[in] amount: The number of bits to shift to the left. + * \return The left-shifted floatl number. + */ +static floatl floatl_int_shl(floatl a, uint32_t amount) +{ + floatl 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 floatl number + for (int i = 0; i < __FLOATL_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 floatl number by a specified number of bits. + * + * This function performs a right bitwise shift on a 128-bit integer + * (floatl). 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 floatl number to shift. + * \param[in] amount: The number of bits to shift to the right. + * \return The right-shifted floatl number. + */ +static floatl floatl_int_shr(floatl a, uint32_t amount) +{ + floatl 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 floatl number + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + // Check if the current index is beyond the range for valid shifts + if (i > __FLOATL_U32_PARTS__ - u32bias - 1 && __FLOATL_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) < __FLOATL_U32_PARTS__ && bitsbias > 0) ? + (a.u32[i + u32bias + 1] << (32 - bitsbias)) : + ((a.u32[__FLOATL_U32_PARTS__ - 1] & 0x80000000) ? 0xFFFFFFFF : 0)); + } + } + + return result; // Return the right-shifted result +} + +/** + * \brief Performs bitwise AND operation on two floatl numbers. + * + * This function computes the bitwise AND of two 128-bit integers + * (floatl). It processes each 32-bit part of the input integers and + * performs the AND operation on corresponding parts, storing the + * result in a new floatl number. This operation yields a number that + * has bits set only where both operands have bits set. + * + * \param[in] a: The first operand (floatl number). + * \param[in] b: The second operand (floatl number). + * \return The result of a AND b as an floatl (128-bit integer). + */ +static floatl floatl_int_and(floatl a, floatl b) +{ + floatl result; // Initialize the result variable + // Perform the bitwise AND operation for each 32-bit part + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + result.u32[i] = a.u32[i] & b.u32[i]; // Compute AND for each part + } + return result; // Return the resulting floatl number +} + +/** + * \brief Performs bitwise OR operation on two floatl numbers. + * + * This function computes the bitwise OR of two 128-bit integers + * (floatl). It processes each 32-bit part of the input integers and + * performs the OR operation on corresponding parts, storing the + * result in a new floatl 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 (floatl number). + * \param[in] b: The second operand (floatl number). + * \return The result of a OR b as an floatl (128-bit integer). + */ +static floatl floatl_int_or(floatl a, floatl b) +{ + floatl result; // Initialize the result variable + // Perform the bitwise OR operation for each 32-bit part + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + result.u32[i] = a.u32[i] | b.u32[i]; // Compute OR for each part + } + return result; // Return the resulting floatl number +} + +/** + * \brief Performs bitwise XOR operation on two floatl numbers. + * + * This function computes the bitwise XOR of two 128-bit integers + * (floatl). It processes each 32-bit part of the input integers and + * performs the XOR operation on corresponding parts, storing the + * result in a new floatl 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 (floatl number). + * \param[in] b: The second operand (floatl number). + * \return The result of a XOR b as an floatl (128-bit integer). + */ +static floatl floatl_int_xor(floatl a, floatl b) +{ + floatl result; // Initialize the result variable + // Perform the bitwise XOR operation for each 32-bit part + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + result.u32[i] = a.u32[i] ^ b.u32[i]; // Compute XOR for each part + } + return result; // Return the resulting floatl number +} + +/** + * \brief Performs bitwise NOT operation on an floatl number. + * + * This function computes the bitwise NOT (negation) of a 128-bit + * integer (floatl). It processes each 32-bit part of the input integer + * and applies the NOT operation, storing the result in a new floatl + * number. This operation inverts all bits of the input number. + * + * \param[in] a: The floatl number to negate. + * \return The bitwise negation of a as an floatl (128-bit integer). + */ +static floatl floatl_int_not(floatl a) +{ + floatl result; // Initialize the result variable + // Perform the bitwise NOT operation for each 32-bit part + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + result.u32[i] = ~a.u32[i]; // Compute NOT for each part + } + return result; // Return the resulting floatl number +} + +/** + * \brief Computes the absolute value of an floatl number. + * + * This function checks if the given 128-bit unsigned integer (floatl) + * 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 + * floatl_int_neg to return its positive equivalent. If the number is + * already non-negative, it simply returns the original number. + * + * \param[in] a: The floatl number for which to compute the absolute value. + * \return The absolute value of the floatl number a. + */ +static floatl floatl_int_abs(floatl a) +{ + // Check if the sign bit of the highest 32-bit part is set + if (a.u32[__FLOATL_U32_PARTS__ - 1] & 0x80000000) + return floatl_int_neg(a); // Return negated value if negative + return a; // Return the original value if non-negative +} + +/** + * \brief Determines the sign of an floatl number. + * + * This function checks the sign of the given 128-bit unsigned integer + * (floatl) 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 floatl 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. + */ +static int floatl_int_sign(floatl a) +{ + // Check if the sign bit of the highest 32-bit part is set + if (a.u32[__FLOATL_U32_PARTS__ - 1] & 0x80000000) return -1; + + // Check if the number is zero + for (int i = __FLOATL_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 Compares two floatl unsigned numbers. + * + * This function compares two 128-bit unsigned integers (floatl) + * 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 floatl_int_ucmp(floatl a, floatl b) +{ + // Compare each 32-bit part from the most significant to the least significant + for (int i = __FLOATL_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 floatl numbers. + * + * This function compares two 128-bit integers (floatl) 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. + */ +static int floatl_int_cmp(floatl a, floatl b) +{ + // Compare each 32-bit part from the most significant to the least significant + for (int i = __FLOATL_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 floatl number. + * + * This function calculates the negative representation of a given 128-bit + * unsigned integer (floatl) 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 floatl number to negate. + * \return The negated floatl number (two's complement of a). + */ +static floatl floatl_int_neg(floatl a) +{ + floatl result = {0}; + + // First, bitwise NOT (invert) the input number + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + result.u32[i] = ~a.u32[i]; + } + + // Add one to complete the two's complement operation + return floatl_int_inc(result); +} + +/** + * \brief Compares two floatl unsigned numbers. + * + * This function compares two 128-bit unsigned integers (floatl) + * 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 floatl2_int_ucmp(floatl2 a, floatl2 b) +{ + // Compare each 32-bit part from the most significant to the least significant + for (int i = __FLOATL2_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 Right shifts an floatl number by a specified number of bits. + * + * This function performs a right bitwise shift on a 128-bit integer + * (floatl). 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 floatl number to shift. + * \param[in] amount: The number of bits to shift to the right. + * \return The right-shifted floatl number. + */ +static floatl2 floatl2_int_shr(floatl2 a, uint32_t amount) +{ + floatl2 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 floatl number + for (int i = 0; i < __FLOATL2_U32_PARTS__; i++) + { + // Check if the current index is beyond the range for valid shifts + if (i > __FLOATL2_U32_PARTS__ - u32bias - 1 && __FLOATL2_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) < __FLOATL2_U32_PARTS__ && bitsbias > 0) ? + (a.u32[i + u32bias + 1] << (32 - bitsbias)) : + ((a.u32[__FLOATL2_U32_PARTS__ - 1] & 0x80000000) ? 0xFFFFFFFF : 0)); + } + } + + return result; // Return the right-shifted result +} + +/** + * \brief Left shifts an floatl number by a specified number of bits. + * + * This function performs a left bitwise shift on a 128-bit integer + * (floatl). 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 floatl number to shift. + * \param[in] amount: The number of bits to shift to the left. + * \return The left-shifted floatl number. + */ +static floatl2 floatl2_int_shl(floatl2 a, uint32_t amount) +{ + floatl2 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 floatl number + for (int i = 0; i < __FLOATL2_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 Determines the sign of an floatl number. + * + * This function checks the sign of the given 128-bit unsigned integer + * (floatl) 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 floatl 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. + */ +static int floatl2_int_sign(floatl2 a) +{ + // Check if the sign bit of the highest 32-bit part is set + if (a.u32[__FLOATL2_U32_PARTS__ - 1] & 0x80000000) return -1; + + // Check if the number is zero + for (int i = __FLOATL2_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 Adds two floatl numbers. + * + * This function computes the sum of two 128-bit integers + * (floatl). It processes each 16-bit part of the input integers, + * handling carry bits as necessary. The result is stored in a + * new floatl number. This function ensures that overflow is + * correctly managed across all parts. + * + * \param[in] a: The first operand (floatl number). + * \param[in] b: The second operand (floatl number). + * \return The sum of a and b as an floatl (128-bit integer). + */ +static floatl2 floatl2_int_add(floatl2 a, floatl2 b) +{ + floatl2 result; // Initialize the result variable + uint16_t carry = 0; /** Carry bit */ + + // Perform addition for each 16-bit part + for (int i = 0; i < __FLOATL2_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 floatl number +} + +/** + * \brief Subtracts one floatl number from another. + * + * This function computes the difference of two 128-bit integers + * (floatl). It processes each 16-bit part of the minuend and + * subtrahend, handling borrow bits as necessary. The result is + * stored in a new floatl 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 floatl (128-bit integer). + */ +static floatl2 floatl2_int_sub(floatl2 a, floatl2 b) +{ + floatl2 result; // Initialize the result variable + + // Perform subtraction for each 16-bit part + for (int i = 0; i < __FLOATL2_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 < __FLOATL2_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 floatl number +} + +/** + * \brief Multiplies two floatl unsigned numbers. + * + * This function performs multiplication of two 128-bit unsigned integers + * (floatl) 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 floatl (128-bit unsigned integer). + */ +static floatl2 floatl2_int_umul(floatl2 a, floatl2 b) +{ + floatl2 result = {0}; /** Initialize the result to 0 */ + floatl2 temp[__FLOATL_U16_PARTS__*2] = {{0}}; // Temporary storage for intermediate results + uint16_t carry = 0; // Variable to hold carry-over during multiplication + + // Perform multiplication + for (int i = 0; i < __FLOATL2_U16_PARTS__; i++) + { + carry = 0; // Reset carry for the current row + for (int j = 0; j < __FLOATL2_U16_PARTS__; j++) + { + if (i + j < __FLOATL2_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 < __FLOATL2_U16_PARTS__; i++) + { + uint32_t add = 0; // Variable to hold the sum of the current column + for (int j = 0; j < __FLOATL2_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 Divides one floatl unsigned number by another. + * + * This function performs division of one 128-bit unsigned integer (floatl) + * 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 floatl (128-bit unsigned integer). + */ +static floatl2 floatl2_int_udiv(floatl2 a, floatl2 b, floatl2 *mod) +{ + int FLOATL2_BIT_PARTS = __FLOATL_BIT_PARTS__ * 2; + // Check for division by zero + if (floatl2_int_sign(b) == 0) + { + printf("Division by zero!\n"); + return FLOATL2(__FLOATL_INT_ZERO__); /** Handle division by zero */ + } + + floatl2 result = {0}; // Initialize the result to zero + floatl2 remainder = {0}; // Initialize the remainder to zero + + /** Calculate bit by bit from the highest bit */ + for (int i = FLOATL2_BIT_PARTS - 1; i >= 0; i--) + { + /** Left shift remainder and add current bit */ + remainder = floatl2_int_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 (floatl2_int_ucmp(remainder, b) >= 0) + { + remainder = floatl2_int_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 Calculate 10 raised to the power of the given integer exponent. + * \param[in] n: The exponent to which 10 is raised. It can be a positive or negative 32 - bit integer. + * \return A 'floatl' value representing 10^n. + * + * This function calculates 10^n by dividing the exponent into segments of 15. + * For positive exponents, it multiplies the result by pre - computed powers of 10. + * For negative exponents, it divides the result by pre - computed powers of 10. + */ +static floatl floatl_pow10(int32_t n) +{ + // Initialize the result to 1 (10^0) + floatl number = FLOATL_CONST_1; + + if (n > 0) + { + // Calculate 10^n for positive exponents, dividing the exponent into segments of 15 + while (n != 0) + { + if (n > 15) { + // If the exponent is greater than 15, multiply the result by 10^15 and reduce the exponent by 15 + number = floatl_mul(number, flpow10[15]); + n -= 15; + } + else { + // If the remaining exponent is less than or equal to 15, multiply the result by 10^n + number = floatl_mul(number, flpow10[n]); + n = 0; + } + } + } + else if (n < 0) + { + // Calculate 10^n for negative exponents, dividing the exponent into segments of 15 + while (n != 0) + { + if (n < -15) { + // If the absolute value of the exponent is greater than 15, divide the result by 10^15 and increase the exponent by 15 + number = floatl_div(number, flpow10[15]); + n += 15; + } + else { + // If the absolute value of the remaining exponent is less than or equal to 15, divide the result by 10^(-n) + number = floatl_div(number, flpow10[-n]); + n = 0; + } + } + } + + return number; +} + +/** + * \brief Convert a hexadecimal character to its corresponding numerical value. + * \param[in] c: The hexadecimal character to be converted. It can be a digit from '0' to '9', + * a lowercase letter from 'a' to 'f', or an uppercase letter from 'A' to 'F'. + * \return The numerical value corresponding to the hexadecimal character. Returns -1 if the input + * character is not a valid hexadecimal character. + * + * This function takes a single hexadecimal character and converts it to its numerical equivalent. + * For digits '0' - '9', it returns the digit value. For letters 'a' - 'f' or 'A' - 'F', it returns + * the corresponding value from 10 to 15. + */ +static char hexI(char c) +{ + // Check if the character is a digit from '0' to '9' + if (c >= '0' && c <= '9') { + // If it is a digit, return its numerical value + return c - '0'; + } + // Check if the character is a lowercase letter from 'a' to 'f' + else if (c >= 'a' && c <= 'f') { + // If it is a lowercase letter, return the corresponding value (10 - 15) + return c - 'a' + 10; + } + // Check if the character is an uppercase letter from 'A' to 'F' + else if (c >= 'A' && c <= 'F') { + // If it is an uppercase letter, return the corresponding value (10 - 15) + return c - 'A' + 10; + } + // If the character is not a valid hexadecimal character, return -1 + return -1; +} + +/** + * \brief Fill the mantissa area of a 'floatl' number with a character value. + * \param[in,out] number: Pointer to the 'floatl' structure where the mantissa will be updated. + * \param[in,out] part: Pointer to an integer representing the current u32 part index in the mantissa area. + * \param[in,out] bitoffset: Pointer to an integer representing the current bit offset within the u32 part. + * \param[in,out] bitnum: Pointer to an integer representing the number of bits to fill. + * \param[in] c: The character value to be filled into the mantissa area. + * \return 1 if the filling operation is successful, 0 if an error occurs (e.g., part index goes out of bounds). + * + * This function takes a character value and fills it into the mantissa area of a 'floatl' number. + * It handles the bit offset and part index to ensure the value is placed correctly in the mantissa. + */ +static int pad_mant(floatl *number, int *part, int *bitoffset, int *bitnum, char c) +{ + // Update the remaining number of bits at the current bit offset + (*bitoffset) -= (*bitnum); + + // If the bit offset is negative, we need to move to the previous u32 part + if ((*bitoffset) < 0) + { + (*part)--; + + // If the u32 part index becomes negative, we need to adjust further + if ((*part) < 0) + { + // Check if the total number of bits to fill is exactly 32. If so, return an error. + if ((*bitoffset) + (*bitnum) == 32) return 0; + else + { + // Reset the part index to 0 + (*part) = 0; + // Adjust the number of bits to fill based on the remaining space in the previous part + (*bitnum) -= (32 - (*bitoffset)); + // Reset the bit offset to 0 + (*bitoffset) = 0; + } + } + + // Update the bit offset within the current part + (*bitoffset) += 32; + } + + // If the current part belongs to the mantissas array + if ((*part) < __FLOATL_MANT_PARTS__) + { + // Concatenate the character 'c' to the mantissas array + number->mantissas[(*part)] |= (c << (*bitoffset)); + + // If there isn't enough space in the current u32 part to fit the entire character, + // we need to continue filling the remaining part into the next higher u32 part + if ((*bitoffset) + (*bitnum) >= 32) + { + // If there is a next part in the mantissas array, fill the remaining part there + if ((*part) + 1 < __FLOATL_MANT_PARTS__) number->mantissas[(*part) + 1] |= (c >> (32 - (*bitoffset))); + // Otherwise, fill the remaining part into the high - order mantissa + else number->mantissa |= (c >> (32 - (*bitoffset))); + } + } + // If the current part belongs to the high - order mantissa + else + { + // Concatenate the character 'c' to the high - order mantissa + number->mantissa |= (c << (*bitoffset)); + } + + return 1; +} + +/** + * \brief Convert a string representation of a floating - point number to a 'floatl' type. + * \param[in] str: Pointer to the null - terminated string representing the floating - point number. + * \return A 'floatl' value representing the converted floating - point number. Returns FLOATL_NAN if the input string is invalid. + * + * This function parses a string to create a 'floatl' number. It supports both hexadecimal (starting with "0x") + * and decimal formats. It handles signs, integer parts, decimal parts, and exponents appropriately. + */ +floatl floatl_from(const char *str) +{ + // Initialize the result number to 0 + floatl number = FLOATL_CONST_0; + const char *text = str; + int sign = 1, scale = 0; /* Sign and scale of integer part */ + int e_sign = 1, e_scale = 0; /* Sign and scale of exponent part */ + int p_sign = 1, p_scale = 0; /* Sign and scale of pico part */ + + // Skip leading whitespace characters + while (*text <= ' ') text++; + + // Check if the number is negative + if (*text == '-') + { + sign = -1; + text++; + } + + // Check if the number starts with '0' + if (*text == '0') + { + // Skip leading '0's + while (*text == '0') text++; + + // Check if it is a hexadecimal number (starts with "0x" or "0X") + if (*text == 'x' || *text == 'X') + { + text++; + + // Skip leading '0's after "0x" + while (*text == '0') text++; + + char c = 0; + char hide = 0; + int exp = 0; + int part = __FLOATL_MANT_PARTS__; + int bitoffset = __FLOATL_MANT_HIGH_BITS__; + int bitnum = 0; + + // Parse the integer part of the hexadecimal number + while (1) + { + c = hexI(*text); + if (c < 0) break; + text++; + + // For the first digit, remove the hidden bit + if (!hide) + { + bitnum = 32 - count_u32_leading_zero(c) - 1; + c &= ((1 << bitnum) - 1); + hide = 1; + } + else bitnum = 4; + + if (!pad_mant(&number, &part, &bitoffset, &bitnum, c)) break; + + exp += bitnum; + } + + // Parse the decimal part of the hexadecimal number + if (*text == '.') + { + text++; + + while (1) + { + c = hexI(*text); + if (c < 0) break; + text++; + + // For the first digit, remove the hidden bit + if (!hide) + { + if (c == 0) + { + exp -= 4; + continue; + } + else + { + bitnum = 32 - count_u32_leading_zero(c) - 1; + exp -= (4 - bitnum); + c &= ((1 << bitnum) - 1); + hide = 1; + } + } + else bitnum = 4; + + if (!pad_mant(&number, &part, &bitoffset, &bitnum, c)) break; + } + } + + // Parse the pico part (exponent part in hexadecimal format) + if (*text == 'p' || *text == 'P') + { + text++; + + // Skip '+' sign + if (*text == '+') text++; + // Handle '-' sign + else if (*text == '-') + { + p_sign = -1; + text++; + } + + // Check if the first character of the exponent is a valid digit + if (!(*text >= '0' && *text <= '9')) + { + return FLOATL_NAN; + } + + // Convert the exponent part + while (*text >= '0' && *text <= '9') + { + p_scale = (p_scale * 10) + (*text++ - '0'); /* number */ + } + } + + // Apply the sign to the pico part + if (p_sign < 0) p_scale = -p_scale; + + // Update the exponent + exp += p_scale; + + // Check for overflow + if (exp > __FLOATL_EXP_MID_VALUE__) + { + floatl inf = FLOATL_INF; + inf.sign = sign > 0 ? 0 : 1; + return inf; + } + // Check for underflow + else if (exp < -__FLOATL_EXP_MID_VALUE__ - 1) + { + floatl zoro = FLOATL_CONST_0; + zoro.sign = sign > 0 ? 0 : 1; + return zoro; + } + + // Set the sign and exponent of the result number + number.sign = sign > 0 ? 0 : 1; + number.exponent = __FLOATL_EXP_MID_VALUE__ + exp; + + return number; + } + } + + // Parse the integer part of the decimal number + if (*text >= '1' && *text <= '9') + { + do + { + // Multiply the number by 10 and add the current digit + number = floatl_mul(number, FLOATL_CONST_10); /* carry addition */ + number = floatl_add(number, floatl_from_d((double)(*text++ - '0'))); + } while (*text >= '0' && *text <= '9'); + } + + // Parse the decimal part of the decimal number + if (*text == '.') + { + text++; + + // Check if the first character of the decimal part is a valid digit + if (!(*text >= '0' && *text <= '9')) + { + return FLOATL_NAN; + } + + // Multiply the number by 10 and add the current digit, and adjust the scale + do + { + number = floatl_mul(number, FLOATL_CONST_10); + number = floatl_add(number, floatl_from_d((double)(*text++ - '0'))); + scale--; + } while (*text >= '0' && *text <= '9'); + } + + // Parse the exponent part of the decimal number + if (*text == 'e' || *text == 'E') + { + text++; + + // Skip '+' sign + if (*text == '+') text++; + // Handle '-' sign + else if (*text == '-') + { + e_sign = -1; + text++; + } + + // Check if the first character of the exponent is a valid digit + if (!(*text >= '0' && *text <= '9')) + { + return FLOATL_NAN; + } + + // Convert the exponent part + while (*text >= '0' && *text <= '9') + { + e_scale = (e_scale * 10) + (*text++ - '0'); /* number */ + } + } + + // Calculate the final result + number = floatl_mul(number, floatl_pow10(scale + e_scale * e_sign)); + number.sign = sign > 0 ? 0 : 1; + + return number; +} + +/** + * \brief Convert a single - precision floating - point number (float) to a 'floatl' type. + * \param[in] value: The single - precision floating - point number to be converted. + * \return A 'floatl' value representing the converted number. Returns FLOATL_NAN if the input is NaN, + * FLOATL_INF if the input is infinity, and the converted value otherwise. + * + * This function takes a float value and converts it to a 'floatl' value. It first checks if the input + * is NaN or infinity and sets the result accordingly. Otherwise, it extracts the mantissa and exponent + * from the float and adjusts them to fit the 'floatl' format. + */ +floatl floatl_from_f(float value) +{ + // Initialize the result to 0 + floatl result = {0}; + // Union to access the float value as an integer and its components + float_u f = {.float_ = value}; + + // Check if the input is NaN + if ((f.int_ & 0x7fffffff) > 0x7f800000) + { + result = FLOATL_NAN; + } + // Check if the input is infinity + else if ((f.int_ & 0x7fffffff) == 0x7f800000) + { + result = FLOATL_INF; + } + else + { + // Extract the mantissa from the float and store it in the 'floatl' mantissa + result.mantissas[0] = f.mantissa; + // Shift the mantissa to the appropriate position in the 'floatl' format + result = floatl_int_shl(result, __FLOATL_MANT_BITS__ - 23); + // Adjust the exponent to fit the 'floatl' format + result.exponent = (uint32_t)(((int32_t)f.exponent - 127) + __FLOATL_EXP_MID_VALUE__); + } + + // Set the sign of the 'floatl' result + result.sign = f.sign; + + return result; +} + +/** + * \brief Convert a double - precision floating - point number (double) to a 'floatl' type. + * \param[in] value: The double - precision floating - point number to be converted. + * \return A 'floatl' value representing the converted number. Returns FLOATL_NAN if the input is NaN, + * FLOATL_INF if the input is infinity, and the converted value otherwise. + * + * This function takes a double value and converts it to a 'floatl' value. It first checks if the input + * is NaN or infinity and sets the result accordingly. Otherwise, it extracts the mantissa and exponent + * from the double and adjusts them to fit the 'floatl' format. + */ +floatl floatl_from_d(double value) +{ + // Initialize the result to 0 + floatl result = {0}; + // Union to access the double value as its components + double_u f = {.float_ = value}; + + // Check if the input is NaN + if (f.exponent == 2047 && (f.mantissa_h != 0 || f.mantissa_l != 0)) + { + result = FLOATL_NAN; + } + // Check if the input is infinity + else if (f.exponent == 2047 && (f.mantissa_h == 0 && f.mantissa_l == 0)) + { + result = FLOATL_INF; + } + else + { + // Extract the low and high parts of the mantissa from the double and store them in the 'floatl' mantissa + result.mantissas[0] = f.mantissa_l; + result.mantissas[1] = f.mantissa_h; + // Shift the mantissa to the appropriate position in the 'floatl' format + result = floatl_int_shl(result, __FLOATL_MANT_BITS__ - 52); + // Adjust the exponent to fit the 'floatl' format + result.exponent = (uint32_t)(((int32_t)f.exponent - 1023) + __FLOATL_EXP_MID_VALUE__); + } + + // Set the sign of the 'floatl' result + result.sign = f.sign; + + return result; +} + +/** + * \brief Get the sign of a 'floatl' number. + * \param[in] a: The 'floatl' number whose sign is to be determined. + * \return The sign of the 'floatl' number. It returns the value of the 'sign' field in the 'floatl' structure. + * + * This function simply extracts and returns the sign bit of the given 'floatl' number. + */ +int floatl_sign(floatl a) +{ + return a.sign; +} + +/** + * \brief Check if a 'floatl' number is NaN (Not a Number). + * \param[in] a: The 'floatl' number to be checked. + * \return 1 if the 'floatl' number is NaN, 0 otherwise. + * + * This function checks if the 'floatl' number is NaN by performing a bitwise AND operation + * between the number and a mask (__FLOATL_ALL_EXP_MANT__) and then comparing the result + * with the representation of infinity (__FLOATL_INF__). If the result is greater than the + * infinity representation, the number is considered NaN. + */ +int floatl_isnan(floatl a) +{ + return floatl_int_ucmp(floatl_int_and(a, __FLOATL_ALL_EXP_MANT__), __FLOATL_INF__) > 0; +} + +/** + * \brief Check if a 'floatl' number is infinity. + * \param[in] a: The 'floatl' number to be checked. + * \return 1 if the 'floatl' number is infinity, 0 otherwise. + * + * This function checks if the 'floatl' number is infinity by performing a bitwise AND operation + * between the number and a mask (__FLOATL_ALL_EXP_MANT__) and then comparing the result + * with the representation of infinity (__FLOATL_INF__). If the result is equal to the + * infinity representation, the number is considered infinity. + */ +int floatl_isinf(floatl a) +{ + return floatl_int_ucmp(floatl_int_and(a, __FLOATL_ALL_EXP_MANT__), __FLOATL_INF__) == 0; +} + +/** + * \brief Check if a 'floatl' number is a normal number. + * \param[in] a: The 'floatl' number to be checked. + * \return 1 if the 'floatl' number is a normal number, 0 otherwise. + * + * A normal number is defined as a number whose exponent is neither 0 nor the maximum possible + * exponent value (__FLOATL_EXP_WHL_VALUE__). This function checks these conditions and + * returns the appropriate result. + */ +int floatl_isnormal(floatl a) +{ + return ((a.exponent != 0) && (a.exponent != __FLOATL_EXP_WHL_VALUE__)); +} + +/** + * \brief Compare if a 'floatl' number 'a' is less than another 'floatl' number 'b'. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return true if 'a' is less than 'b', false otherwise. + * + * This function compares two 'floatl' numbers to determine if 'a' is less than 'b'. + * It first checks the signs of the two numbers. If the signs are different, + * it checks if 'a' is negative and the result of a bit - shifted OR operation of 'a' and 'b' is non - zero. + * If the signs are the same, it checks if the two numbers are not equal and applies a condition based on the sign. + */ +static bool floatl_real_lt(floatl a, floatl b) +{ + // Extract the sign of 'a' + bool sign1 = a.sign; + // Extract the sign of 'b' + bool sign2 = b.sign; + // Check if the signs of the two numbers are different + if (sign1 != sign2) // This can also be checked using XOR + { + // If 'a' is negative and the result of a bit - shifted OR operation of 'a' and 'b' is non - zero, + // then 'a' is less than 'b' + return sign1 && floatl_int_sign(floatl_int_shl(floatl_int_or(a, b), 1)); + } + // If the signs are the same, 'a' is less than 'b' if the two numbers are not equal + // and for positive numbers, the one with a smaller absolute value is smaller, + // while for negative numbers, the one with a larger absolute value is smaller + return (floatl_int_ucmp(a, b)) && (sign1 ^ (floatl_int_ucmp(a, b) < 0)); +} + +/** + * \brief Compare if a 'floatl' number 'a' is less than or equal to another 'floatl' number 'b'. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return true if 'a' is less than or equal to 'b', false otherwise. + * + * This function compares two 'floatl' numbers to determine if 'a' is less than or equal to 'b'. + * It first checks the signs of the two numbers. If the signs are different, + * it checks if 'a' is negative or the result of a bit - shifted OR operation of 'a' and 'b' is zero. + * If the signs are the same, it checks if the two numbers are equal or the appropriate condition based on the sign holds. + */ +static bool floatl_real_le(floatl a, floatl b) +{ + // Extract the sign of 'a' + bool sign1 = a.sign; + // Extract the sign of 'b' + bool sign2 = b.sign; + // Check if the signs of the two numbers are different + if (sign1 != sign2) + { + // Different from the 'lt' function, the numbers can be zero here. + // If 'a' is negative or the result of a bit - shifted OR operation of 'a' and 'b' is zero, + // then 'a' is less than or equal to 'b' + return sign1 || (floatl_int_sign(floatl_int_shl(floatl_int_or(a, b), 1)) == 0); + } + // Different from the 'lt' function, we check for equality or less - than condition. + // 'a' is less than or equal to 'b' if the two numbers are equal or the appropriate condition based on the sign holds. + return (!floatl_int_ucmp(a, b)) || (sign1 ^ (floatl_int_ucmp(a, b) < 0)); +} + +/** + * \brief Check if two 'floatl' numbers are equal. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return 1 if the two numbers are equal, 0 otherwise. + * + * This function first checks if either of the numbers is a NaN (Not a Number). + * If so, it immediately returns 0 because NaN is not equal to any number, including itself. + * Otherwise, it checks if the two numbers are equal by comparing their bit - representations + * using floatl_int_ucmp. It also considers the case where both numbers might be zero + * by using floatl_int_sign and floatl_int_shl along with floatl_int_or. + */ +int floatl_eq(floatl a, floatl b) +{ + // If either number is a NaN, they are not equal + if (floatl_isnan(a) || floatl_isnan(b)) + return 0; + return + // Check if the bit - representations of the two numbers are equal + (!floatl_int_ucmp(a, b)) || + // Check if both numbers are effectively zero + ((floatl_int_sign(floatl_int_shl(floatl_int_or(a, b), 1)) == 0)); +} + +/** + * \brief Check if two 'floatl' numbers are not equal. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return 1 if the two numbers are not equal, 0 otherwise. + * + * This function simply negates the result of the floatl_eq function. + * If floatl_eq returns 1 (equal), this function returns 0 (not equal), and vice versa. + */ +int floatl_ne(floatl a, floatl b) +{ + return !floatl_eq(a, b); +} + +/** + * \brief Check if the first 'floatl' number is less than the second. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return 1 if a < b, 0 otherwise. + * + * This function first checks if either of the numbers is a NaN. + * If so, it returns 0 because NaN cannot be compared in a meaningful way. + * Otherwise, it calls the floatl_real_lt function to perform the actual less - than comparison. + */ +int floatl_lt(floatl a, floatl b) +{ + if (floatl_isnan(a) || floatl_isnan(b)) + return 0; + return floatl_real_lt(a, b); +} + +/** + * \brief Check if the first 'floatl' number is less than or equal to the second. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return 1 if a <= b, 0 otherwise. + * + * This function first checks if either of the numbers is a NaN. + * If so, it returns 0. Otherwise, it calls the floatl_real_le function + * to perform the actual less - than or equal comparison. + */ +int floatl_le(floatl a, floatl b) +{ + if (floatl_isnan(a) || floatl_isnan(b)) + return 0; + return floatl_real_le(a, b); +} + +/** + * \brief Check if the first 'floatl' number is greater than the second. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return 1 if a > b, 0 otherwise. + * + * This function first checks if either of the numbers is a NaN. + * If so, it returns 0. Otherwise, it negates the result of the floatl_real_le function + * because a > b is equivalent to!(a <= b). + */ +int floatl_gt(floatl a, floatl b) +{ + if (floatl_isnan(a) || floatl_isnan(b)) + return 0; + return !floatl_real_le(a, b); +} + +/** + * \brief Check if the first 'floatl' number is greater than or equal to the second. + * \param[in] a: The first 'floatl' number to be compared. + * \param[in] b: The second 'floatl' number to be compared. + * \return 1 if a >= b, 0 otherwise. + * + * This function first checks if either of the numbers is a NaN. + * If so, it returns 0. Otherwise, it negates the result of the floatl_real_lt function + * because a >= b is equivalent to!(a < b). + */ +int floatl_ge(floatl a, floatl b) +{ + if (floatl_isnan(a) || floatl_isnan(b)) + return 0; + return !floatl_real_lt(a, b); +} + +/** + * \brief Compute the absolute value of a 'floatl' number. + * \param[in] a: The 'floatl' number for which the absolute value is to be computed. + * \return A 'floatl' number representing the absolute value of the input number. + * + * This function takes a 'floatl' number and checks its sign bit. If the number is negative + * (i.e., the sign bit is set), it clears the sign bit to make the number positive. + * If the number is already positive, it remains unchanged. + */ +floatl floatl_abs(floatl a) +{ + // Check if the number is negative + if (a.sign) + // If negative, set the sign bit to 0 (make it positive) + a.sign = 0; + return a; +} + +/** + * \brief Compute the negation of a 'floatl' number. + * \param[in] a: The 'floatl' number to be negated. + * \return A 'floatl' number representing the negation of the input number. + * + * This function takes a 'floatl' number and toggles its sign bit. If the number is positive, + * it becomes negative; if the number is negative, it becomes positive. + */ +floatl floatl_neg(floatl a) +{ + // Toggle the sign bit of the number + a.sign = !a.sign; + return a; +} + +/** + * \brief Perform a right shift operation on a 'floatl' value while preserving the sticky bit. + * \param[in] mant: The 'floatl' value to be shifted. + * \param[in] n: The number of bits to shift to the right. + * \return A 'floatl' value representing the result of the right shift operation with the sticky bit preserved. + * + * This function performs a right shift operation on the given 'floatl' value. If the number of bits to shift + * is less than the total number of bits in a 'floatl' minus 1, it uses the floatl_int_shr function to perform + * the shift. Then, it checks if there are any non - zero bits that would be shifted out by using floatl_int_sign + * and floatl_int_shl. If so, it sets the least significant bit of the result to 1. If the number of bits to shift + * is greater than or equal to the total number of bits in a 'floatl' minus 1, it checks if the original value + * is non - zero and sets the least significant bit of the result accordingly. + */ +static floatl shift_right_sticky(floatl mant, uint32_t n) +{ + // Initialize the result to zero + floatl res = __FLOATL_INT_ZERO__; + if (n < __FLOATL_BIT_PARTS__ - 1) { + // Perform the right shift operation + res = floatl_int_shr(mant, n); + // Check if there are non - zero bits shifted out + if (floatl_int_sign(floatl_int_shl(mant, __FLOATL_BIT_PARTS__ - n))) + { + // Set the least significant bit of the result + res.u32[0] |= 1; + } + } + else { + // Check if the original value is non - zero + if (floatl_int_sign(mant)) + { + // Set the least significant bit of the result + res.u32[0] |= 1; + } + } + return res; +} + +/** + * \brief Perform a right shift operation on the product of two 'floatl' values while preserving the sticky bit. + * \param[in] mant1: The first 'floatl' value. + * \param[in] mant2: The second 'floatl' value. + * \return A 'floatl' value representing the result of the right shift operation on the product of the two 'floatl' values + * with the sticky bit preserved. + * + * This function first multiplies the two given 'floatl' values using floatl2_int_umul and stores the result in a 'floatl2' + * structure. Then, it performs a right shift operation on the product using floatl2_int_shr. It checks if there are any + * non - zero bits that would be shifted out by using floatl2_int_sign and floatl2_int_shl. If so, it sets the least + * significant bit of the result. Finally, it returns the lower part of the 'floatl2' result as a 'floatl' value. + */ +static floatl shift_right_sticky_fl2(floatl mant1, floatl mant2) +{ + // Initialize the result and temporary 'floatl2' structures to zero + floatl2 res = {0}; + floatl2 temp = {0}; + + // Multiply the two 'floatl' values + temp = floatl2_int_umul(FLOATL2(mant1), FLOATL2(mant2)); + // Perform the right shift operation on the product + res = floatl2_int_shr(temp, __FLOATL_MANT_BITS__ - 2); + // Check if there are non - zero bits shifted out + if (floatl2_int_sign(floatl2_int_shl(temp, __FLOATL_BIT_PARTS__ * 2 - (__FLOATL_MANT_BITS__ - 2)))) + { + // Set the least significant bit of the result + res.u32[0] |= 1; + } + + // Return the lower part of the 'floatl2' result + return res.low; +} + +/** + * \brief Perform a round - to - even operation on a 'floatl' value using the GRS (Guard, Round, Sticky) bits. + * \param[in] mant: The 'floatl' value to be rounded. + * \return A 'floatl' value representing the result of the round - to - even operation. + * + * This function extracts the lower 3 bits (GRS bits) of the given 'floatl' value. Then, it shifts the 'floatl' value + * to the right by 3 bits. It creates a 'floatl' value with the least significant bit set to 1. Based on the value of + * the GRS bits and the least significant bit of the shifted value, it decides whether to increment the shifted value. + * If the GRS bits are greater than 4 or equal to 4 and the least significant bit of the shifted value is 1, it increments + * the shifted value using floatl_int_inc. Finally, it returns the rounded 'floatl' value. + */ +static floatl round_even_grs(floatl mant) +{ + // Extract the GRS (Guard, Round, Sticky) bits + uint8_t grs = mant.u32[0] & 7; + + // Shift the 'floatl' value to the right by 3 bits + mant = floatl_int_shr(mant, 3); + + // Create a 'floatl' value with the least significant bit set to 1 + floatl u1 = __FLOATL_INT_ZERO__; + u1.u32[0] = 1U; + // Check the conditions for rounding + if ((grs > 4) || ((grs == 4) && (mant.u32[0] & 1))) + // Increment the shifted value if the conditions are met + mant = floatl_int_inc(mant); + + return mant; +} + +/** + * \brief Determine whether the result should be NaN or Inf based on the sign and mantissa. + * \param[in] sign: A boolean value representing the sign. If true, it indicates a negative sign; otherwise, a positive sign. + * \param[in] mant: A 'floatl' type mantissa value used to determine if the result should be NaN. + * \return A 'floatl' value representing either NaN or Inf with the appropriate sign. + * + * This function first initializes the result as infinity. Then, it checks the mantissa. If the mantissa is non - zero, + * it returns NaN. Otherwise, it sets the sign bit of the infinity value and returns the result. + */ +static inline floatl floatl_nan_inf(bool sign, floatl mant) +{ + // Initialize the result as infinity + floatl result = __FLOATL_INF__; + // Check if the mantissa is non - zero. If so, return NaN + if (floatl_int_sign(mant)) + return __FLOATL_NAN__; + // Set the sign bit of the infinity value + result.u32[__FLOATL_U32_PARTS__ - 1] |= ((uint32_t)sign << 31); + return result; +} + +/** + * \brief Count the number of leading zero bits in a 32 - bit unsigned integer. + * \param[in] x: A 32 - bit unsigned integer whose leading zero bits are to be counted. + * \return The number of leading zero bits in the input 32 - bit unsigned integer. + * + * This function uses a binary search - like approach to count the leading zero bits efficiently. + * If the input is zero, it immediately returns 32. Otherwise, it narrows down the search range + * by shifting the number and incrementing a counter accordingly. + */ +static int count_u32_leading_zero(uint32_t x) +{ + // If the input is zero, there are 32 leading zero bits + if (x == 0) + return 32; + int n = 1; + // Check the higher 16 bits. If they are zero, increment the counter and shift the number + if ((x >> 16) == 0) { n += 16; x <<= 16; } + // Check the next 8 bits. If they are zero, increment the counter and shift the number + if ((x >> 24) == 0) { n += 8; x <<= 8; } + // Check the next 4 bits. If they are zero, increment the counter and shift the number + if ((x >> 28) == 0) { n += 4; x <<= 4; } + // Check the next 2 bits. If they are zero, increment the counter and shift the number + if ((x >> 30) == 0) { n += 2; x <<= 2; } + // Adjust the counter based on the most significant bit + n -= (x >> 31); + return n; +} + +/** + * \brief Count the total number of leading zero bits in a 'floatl' type value. + * \param[in] x: A 'floatl' type value whose leading zero bits are to be counted. + * \return The total number of leading zero bits in the input 'floatl' value. + * + * This function iterates over the 32 - bit parts of the 'floatl' value from the most significant part to the least significant part. + * If a part is zero, it adds 32 to the counter. If a non - zero part is found, it counts the leading zero bits in that part + * using the count_u32_leading_zero function and then stops the iteration. + */ +static int count_leading_zero(floatl x) +{ + int n = 0; + + // Iterate over the 32 - bit parts of the 'floatl' value from the most significant part to the least significant part + for (int i = __FLOATL_U32_PARTS__ - 1; i >= 0; i--) + { + if (x.u32[i] == 0) + { + // If the current part is zero, add 32 to the counter + n += 32; + } + else + { + // If the current part is non - zero, count the leading zero bits in this part and break the loop + n += count_u32_leading_zero(x.u32[i]); + break; + } + } + return n; +} + +/** + * \brief Perform addition of two 'floatl' numbers by adding their absolute values. + * The sign of the result is determined by the sign of the first parameter. + * \param[in] a: The first 'floatl' number. + * \param[in] b: The second 'floatl' number. + * \return A 'floatl' number representing the result of the addition. + * + * This function adds the absolute values of two 'floatl' numbers. It first extracts + * the exponents and mantissas of the input numbers. Then it handles special cases + * such as when the exponents are the same, or when one of the numbers is NaN or Inf. + * After that, it aligns the mantissas according to the exponent difference, adds them, + * and performs rounding and normalization steps. Finally, it checks for overflow and + * returns the result with the appropriate sign. + */ +static floatl real_floatl_add(floatl a, floatl b) +{ + // Extract the exponent of the first number + uint32_t exp1 = a.exponent; + // Extract the exponent of the second number + uint32_t exp2 = b.exponent; + // Extract the mantissa of the first number, setting sign and exponent to 0 + floatl mant1 = a; mant1.sign = 0; mant1.exponent = 0U; + // Extract the mantissa of the second number, setting sign and exponent to 0 + floatl mant2 = b; mant2.sign = 0; mant2.exponent = 0U; + // Set the sign of the result to the sign of the first number + bool sign = a.sign; + // Calculate the difference between the exponents + int32_t expdiff = exp1 - exp2; + + // Check if the exponents are the same + if (expdiff == 0) + { + // Handle denormalized numbers + if (exp1 == 0) + { + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Check for infinity or NaN + if (exp1 == __FLOATL_ALL_EXP__.exponent) + { + return floatl_nan_inf(sign, floatl_int_or(mant1, mant2)); + } + } + + // Check if the first number is NaN or Inf + if (exp1 == __FLOATL_ALL_EXP__.exponent) return floatl_nan_inf(sign, mant1); + // Check if the second number is NaN or Inf + if (exp2 == __FLOATL_ALL_EXP__.exponent) return floatl_nan_inf(sign, mant2); + + // If the first number is denormalized, return the second number with the appropriate sign + if (exp1 == 0) + { + b.sign = sign; + return b; + } + + // If the second number is denormalized, return the first number with the appropriate sign + if (exp2 == 0) + { + a.sign = sign; + return a; + } + + // Add the hidden bit (1) to the mantissas + mant1 = floatl_int_or(mant1, __FLOATL_HIDE_MANT_BIT__); + mant2 = floatl_int_or(mant2, __FLOATL_HIDE_MANT_BIT__); + + // Shift the mantissas left by 2 bits + mant1 = floatl_int_shl(mant1, 2); + mant2 = floatl_int_shl(mant2, 2); + + // If the exponent of the first number is smaller + if (expdiff < 0) + { + expdiff = -expdiff; + // Shift the first mantissa right by the exponent difference, preserving the sticky bit + mant1 = shift_right_sticky(mant1, expdiff); + exp1 = exp2; + } + // If the exponent of the first number is larger + else if (expdiff > 0) + { + // Shift the second mantissa right by the exponent difference, preserving the sticky bit + mant2 = shift_right_sticky(mant2, expdiff); + } + + // Add the two mantissas + floatl mant = floatl_int_add(mant1, mant2); + + // Check if the result mantissa is less than the maximum allowed value + if (floatl_int_ucmp(mant, __FLOATL_MANT_PLUS_MAX__) < 0) + { + // Shift the mantissa left by 1 bit + mant = floatl_int_shl(mant, 1); + } + else + { + // Increment the exponent if the mantissa overflows + exp1++; + } + + // Perform round - to - even rounding on the mantissa + mant = round_even_grs(mant); + // Check if the rounded mantissa exceeds the maximum value + if (floatl_int_ucmp(mant, __FLOATL_MANT_WHL__) > 0) + { + // Increment the exponent if the rounded mantissa overflows + exp1++; + } + + // Check for overflow of the exponent + if (exp1 > ((uint32_t)(__FLOATL_ALL_EXP__.exponent) - 1)) + { + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Set the result number with the new mantissa, sign, and exponent + a = mant; + a.sign = sign; + a.exponent = exp1; + + return a; +} + +/** + * \brief Perform subtraction of two 'floatl' numbers by subtracting their absolute values. + * The sign of the result is the sign of the number with the larger absolute value. + * \param[in] a: The first 'floatl' number. + * \param[in] b: The second 'floatl' number. + * \return A 'floatl' number representing the result of the subtraction. + * + * This function subtracts the absolute values of two 'floatl' numbers. It first extracts + * the exponents and mantissas of the input numbers. Then it handles special cases + * such as when the exponents are the same, or when one of the numbers is NaN or Inf. + * After that, it aligns the mantissas according to the exponent difference, subtracts them, + * and performs normalization and rounding steps. Finally, it checks for underflow and + * returns the result with the appropriate sign. + */ +static floatl real_floatl_sub(floatl a, floatl b) +{ + // Extract the exponent of the first number + uint32_t exp1 = a.exponent; + // Extract the exponent of the second number + uint32_t exp2 = b.exponent; + // Extract the mantissa of the first number, setting sign and exponent to 0 + floatl mant1 = a; mant1.sign = 0; mant1.exponent = 0U; + // Extract the mantissa of the second number, setting sign and exponent to 0 + floatl mant2 = b; mant2.sign = 0; mant2.exponent = 0U; + // Initialize the result mantissa to zero + floatl mant = __FLOATL_INT_ZERO__; + // Set the sign of the result to the sign of the first number + bool sign = a.sign; + // Calculate the difference between the exponents + int32_t expdiff = exp1 - exp2; + + // Check if the exponents are the same + if (expdiff == 0) + { + // Return NaN if both exponents represent NaN or Inf + if (exp1 == __FLOATL_ALL_EXP__.exponent) return __FLOATL_NAN__; + + // Return zero if the mantissas are equal + if (floatl_int_ucmp(mant1, mant2) == 0) return __FLOATL_INT_ZERO__; + + // If the first mantissa is larger + if (floatl_int_ucmp(mant1, mant2) > 0) + { + // Subtract the second mantissa from the first + mant = floatl_int_sub(mant1, mant2); + } + else + { + // Subtract the first mantissa from the second and reverse the sign + mant = floatl_int_sub(mant2, mant1); + sign = !sign; + } + // Shift the result mantissa left by 3 bits + mant = floatl_int_shl(mant, 3); + } + // If the exponent of the first number is smaller + else if (expdiff < 0) + { + // Reverse the sign of the result + sign = !sign; + + // Check if the second number is NaN or Inf + if (exp2 == __FLOATL_ALL_EXP__.exponent) return floatl_nan_inf(sign, mant2); + // If the first number is denormalized, return the second number with the appropriate sign + if (exp1 == 0) { b.sign = sign; return b; } + + exp1 = exp2; + expdiff = -expdiff; + // Add the hidden bit to the first mantissa and shift it left by 3 bits + mant1 = floatl_int_shl(floatl_int_or(mant1, __FLOATL_HIDE_MANT_BIT__), 3); + // Shift the first mantissa right by the exponent difference, preserving the sticky bit + mant1 = shift_right_sticky(mant1, expdiff); + // Add the hidden bit to the second mantissa, shift it left by 3 bits, and subtract the first mantissa + mant = floatl_int_sub(floatl_int_shl(floatl_int_or(mant2, __FLOATL_HIDE_MANT_BIT__), 3), mant1); + } + else + { + // Check if the first number is NaN or Inf + if (exp1 == __FLOATL_ALL_EXP__.exponent) return floatl_nan_inf(sign, mant1); + // If the second number is denormalized, return the first number with the appropriate sign + if (exp2 == 0) { a.sign = sign; return a; } + + // Add the hidden bit to the second mantissa and shift it left by 3 bits + mant2 = floatl_int_shl(floatl_int_or(mant2, __FLOATL_HIDE_MANT_BIT__), 3); + // Shift the second mantissa right by the exponent difference, preserving the sticky bit + mant2 = shift_right_sticky(mant2, expdiff); + // Add the hidden bit to the first mantissa, shift it left by 3 bits, and subtract the second mantissa + mant = floatl_int_sub(floatl_int_shl(floatl_int_or(mant1, __FLOATL_HIDE_MANT_BIT__), 3), mant2); + } + + // Count the leading zero bits in the result mantissa and adjust for the exponent bits + int shift = count_leading_zero(mant) - (__FLOATL_EXP_BITS__ - 3); + // Limit the shift to the current exponent value + if (shift > exp1) + { + shift = exp1; + // Shift the mantissa right by 1 bit + mant = floatl_int_shr(mant, 1); + } + // Decrease the exponent by the shift amount + exp1 -= shift; + // Shift the mantissa left by the shift amount + mant = floatl_int_shl(mant, shift); + + // Perform round - to - even rounding on the mantissa + mant = round_even_grs(mant); + // Check if the rounded mantissa exceeds the maximum value + if (floatl_int_ucmp(mant, __FLOATL_MANT_WHL__) > 0) + { + // Increment the exponent if the rounded mantissa overflows + exp1++; + } + + // Check for underflow of the exponent + if (exp1 < 1) + { + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Set the result number with the new mantissa, sign, and exponent + a = mant; + a.sign = sign; + a.exponent = exp1; + + return a; +} + +/** + * \brief Perform addition of two 'floatl' numbers. + * \param[in] a: The first 'floatl' number to be added. + * \param[in] b: The second 'floatl' number to be added. + * \return A 'floatl' number representing the result of the addition. + * + * This function decides whether to perform an actual addition or subtraction based on the signs of the two input numbers. + * If the signs of 'a' and 'b' are the same, it calls the 'real_floatl_add' function to add their absolute values. + * If the signs are different, it calls the 'real_floatl_sub' function to subtract their absolute values. + */ +floatl floatl_add(floatl a, floatl b) +{ + // Check if the signs of the two numbers are the same + if (a.sign == b.sign) + // If the signs are the same, perform addition of absolute values + return real_floatl_add(a, b); + // If the signs are different, perform subtraction of absolute values + return real_floatl_sub(a, b); +} + +/** + * \brief Perform subtraction of two 'floatl' numbers. + * \param[in] a: The minuend 'floatl' number. + * \param[in] b: The subtrahend 'floatl' number. + * \return A 'floatl' number representing the result of the subtraction. + * + * This function determines whether to perform an actual subtraction or addition based on the signs of the two input numbers. + * If the signs of 'a' and 'b' are the same, it calls the 'real_floatl_sub' function to subtract their absolute values. + * If the signs are different, it calls the 'real_floatl_add' function to add their absolute values. + */ +floatl floatl_sub(floatl a, floatl b) +{ + // Check if the signs of the two numbers are the same + if (a.sign == b.sign) + // If the signs are the same, perform subtraction of absolute values + return real_floatl_sub(a, b); + // If the signs are different, perform addition of absolute values + return real_floatl_add(a, b); +} + +/** + * \brief Perform multiplication of two 'floatl' numbers. + * \param[in] a: The first 'floatl' number to be multiplied. + * \param[in] b: The second 'floatl' number to be multiplied. + * \return A 'floatl' number representing the result of the multiplication. + * + * This function multiplies two 'floatl' numbers 'a' and 'b'. It first extracts the exponents and mantissas + * of the input numbers. Then it checks for special cases such as infinity, NaN, and zero. After that, + * it calculates the new exponent and multiplies the mantissas. It performs normalization, rounding, + * and checks for underflow and overflow conditions. Finally, it returns the result with the appropriate sign. + */ +floatl floatl_mul(floatl a, floatl b) +{ + // Extract the exponent of the first number + uint32_t exp1 = a.exponent; + // Extract the exponent of the second number + uint32_t exp2 = b.exponent; + // Extract the mantissa of the first number, setting sign and exponent to 0 + floatl mant1 = a; mant1.sign = 0; mant1.exponent = 0U; + // Extract the mantissa of the second number, setting sign and exponent to 0 + floatl mant2 = b; mant2.sign = 0; mant2.exponent = 0U; + // Determine the sign of the result using XOR + bool sign = a.sign ^ b.sign; + + // Check if the first number is infinity or NaN + if (exp1 == __FLOATL_ALL_EXP__.exponent) + { + // Check for NaN conditions + if (floatl_sign(mant1) || ((exp2 == __FLOATL_ALL_EXP__.exponent) && floatl_sign(mant2)) || (exp2 == 0)) + return __FLOATL_NAN__; + + // Set the result to infinity with the appropriate sign + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Check if the second number is infinity or NaN + if (exp2 == __FLOATL_ALL_EXP__.exponent) + { + // Check for NaN conditions + if (floatl_sign(mant2) || (exp1 == 0)) + return __FLOATL_NAN__; + + // Set the result to infinity with the appropriate sign + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Check if either number is zero + if ((exp1 == 0) || (exp2 == 0)) + { + // Set the result to zero with the appropriate sign + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Initialize the result mantissa to zero + floatl mant = __FLOATL_INT_ZERO__; + // Calculate the new exponent + int32_t exp = exp1 + exp2 - __FLOATL_EXP_MID_VALUE__; + + // Add the hidden bit (1) to the mantissas + mant1 = floatl_int_or(mant1, __FLOATL_HIDE_MANT_BIT__); + mant2 = floatl_int_or(mant2, __FLOATL_HIDE_MANT_BIT__); + + // Multiply the mantissas and perform right shift with sticky bit preservation + mant = shift_right_sticky_fl2(mant1, mant2); + // Check if the result mantissa is less than the maximum allowed value + if (floatl_int_ucmp(mant, __FLOATL_MANT_PLUS_MAX__) < 0) + { + // Shift the mantissa left by 1 bit + mant = floatl_int_shl(mant, 1); + } + else + { + // Increment the exponent if the mantissa overflows + exp++; + } + + // Perform round - to - even rounding on the mantissa + mant = round_even_grs(mant); + // Check if the rounded mantissa exceeds the maximum value + if (floatl_int_ucmp(mant, __FLOATL_MANT_WHL__) > 0) + exp++; + + // Check for underflow of the exponent + if (exp < 1) + { + // Set the result to zero with the appropriate sign + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Check for overflow of the exponent + if (exp > ((uint32_t)__FLOATL_ALL_EXP__.exponent - 1)) + { + // Set the result to infinity with the appropriate sign + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Set the result number with the new mantissa, sign, and exponent + a = mant; + a.sign = sign; + a.exponent = exp; + + return a; +} + +/** + * \brief Perform division of two 'floatl' numbers. + * \param[in] a: The dividend 'floatl' number. + * \param[in] b: The divisor 'floatl' number. + * \return A 'floatl' number representing the result of the division. + * + * This function divides two 'floatl' numbers 'a' by 'b'. It first extracts the exponents and mantissas + * of the input numbers. Then it checks for special cases such as infinity, NaN, and zero. After that, + * it calculates the new exponent and performs the division of the mantissas. It performs normalization, + * rounding, and checks for underflow and overflow conditions. Finally, it returns the result with the appropriate sign. + */ +floatl floatl_div(floatl a, floatl b) +{ + // Extract the exponent of the first number + uint32_t exp1 = a.exponent; + // Extract the exponent of the second number + uint32_t exp2 = b.exponent; + // Extract the mantissa of the first number, setting sign and exponent to 0 + floatl mant1 = a; mant1.sign = 0; mant1.exponent = 0U; + // Extract the mantissa of the second number, setting sign and exponent to 0 + floatl mant2 = b; mant2.sign = 0; mant2.exponent = 0U; + // Determine the sign of the result using XOR + bool sign = a.sign ^ b.sign; + + // Check if the first number is infinity or NaN + if (exp1 == __FLOATL_ALL_EXP__.exponent) + { + // Check for NaN conditions + if (floatl_int_sign(mant1) || (exp2 == __FLOATL_ALL_EXP__.exponent)) + return __FLOATL_NAN__; + + // Set the result to infinity with the appropriate sign + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Check if the second number is infinity or NaN + if (exp2 == __FLOATL_ALL_EXP__.exponent) + { + // Check for NaN conditions + if (floatl_int_sign(mant2)) + return __FLOATL_NAN__; + + // Set the result to zero with the appropriate sign + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Check if the dividend is zero + if (exp1 == 0) + { + // Check for NaN condition (division of zero by zero) + if (exp2 == 0) + return __FLOATL_NAN__; + + // Set the result to zero with the appropriate sign + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Check if the divisor is zero + if (exp2 == 0) + { + // Set the result to infinity with the appropriate sign + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Calculate the new exponent + int32_t exp = exp1 - exp2 + __FLOATL_EXP_MID_VALUE__; + + // Add the hidden bit (1) to the mantissas + mant1 = floatl_int_or(mant1, __FLOATL_HIDE_MANT_BIT__); + mant2 = floatl_int_or(mant2, __FLOATL_HIDE_MANT_BIT__); + + floatl mant; + floatl2 sigl2 = FLOATL2(__FLOATL_INT_ZERO__); + // Check if the dividend mantissa is less than the divisor mantissa + if (floatl_int_ucmp(mant1, mant2) < 0) + { + // Decrease the exponent + exp--; + // Shift the dividend mantissa left by __FLOATL_BIT_PARTS__ bits + sigl2 = floatl2_int_shl(FLOATL2(mant1), __FLOATL_BIT_PARTS__); + } + else + { + // Shift the dividend mantissa left by __FLOATL_BIT_PARTS__ - 1 bits + sigl2 = floatl2_int_shl(FLOATL2(mant1), __FLOATL_BIT_PARTS__ - 1); + } + + floatl2 rem; + // Perform the division of the mantissas and shift the result right + mant = floatl2_int_shr(floatl2_int_udiv(sigl2, FLOATL2(mant2), &rem), __FLOATL_EXP_BITS__ - 3).low; + // Check if there is a non - zero remainder + if (floatl_sign(rem.low)) + { + // Set the least significant bit of the mantissa + mant.u32[0] |= 1; + } + // Perform round - to - even rounding on the mantissa + mant = round_even_grs(mant); + // Check for underflow of the exponent + if (exp < 1) + { + // Set the result to zero with the appropriate sign + a = __FLOATL_INT_ZERO__; + a.sign = sign; + return a; + } + + // Check for overflow of the exponent + if (exp > ((uint32_t)__FLOATL_ALL_EXP__.exponent - 1)) + { + // Set the result to infinity with the appropriate sign + a = __FLOATL_INF__; + a.sign = sign; + return a; + } + + // Set the result number with the new mantissa, sign, and exponent + a = mant; + a.sign = sign; + a.exponent = exp; + + return a; +} + +/** + * \brief Check if the absolute value of the integer part of a 'floatl' number is greater than 1. + * \param[in] num: The 'floatl' number to be checked. + * \return 1 if the absolute value of the integer part is greater than 1 (i.e., the integer part is non - zero), 0 otherwise. + * + * This function first checks if the exponent of the 'floatl' number is 1. If so, it returns 0. + * Then it calculates the actual exponent value by subtracting the mid - value of the exponent range. + * If the calculated exponent is greater than or equal to 0, it means the integer part is non - zero, and it returns 1. + */ +static int LT1(floatl num) +{ + // If the exponent is 1, the integer part is not greater than 1 + if (((uint32_t)num.exponent) == 1) return 0; + // Calculate the actual exponent value + int32_t exp = ((int)num.exponent) - __FLOATL_EXP_MID_VALUE__; + // Check if the actual exponent is non - negative + return exp >= 0; +} + +/** + * \brief Check if the absolute value of the fractional part of a 'floatl' number is less than 1. + * \param[in] num: The 'floatl' number to be checked. + * \return 1 if the absolute value of the fractional part is less than 1 (i.e., the fractional part is non - zero), 0 otherwise. + * + * This function first calculates the actual exponent value by subtracting the mid - value of the exponent range. + * If the calculated exponent is negative, it means the fractional part is non - zero, and it returns 1. + * If the exponent is non - negative and less than the number of mantissa bits, it checks each part of the mantissa + * to see if there are non - zero bits in the fractional part. If so, it returns 1. Otherwise, it returns 0. + */ +static int ST1(floatl num) +{ + // Calculate the actual exponent value + int exp = ((int)num.exponent) - __FLOATL_EXP_MID_VALUE__; + + // If the exponent is negative, the fractional part is non - zero + if (exp < 0) return 1; + + // If the exponent is less than the number of mantissa bits + if (exp < __FLOATL_MANT_BITS__) + { + // Calculate the number of bits in the fractional part + int bits = __FLOATL_MANT_BITS__ - exp; + + // Iterate over each part of the mantissa + for (int i = 0; i < __FLOATL_MANT_PARTS__; i++) + { + if (bits >= 32) + { + // If the number of fractional bits is greater than or equal to 32, check if the current part is non - zero + if (num.mantissas[i] != 0) return 1; + // Decrease the number of remaining fractional bits + bits -= 32; + } + else + { + // Create a mask to check the fractional bits in the current part + if ((num.mantissas[i] & ((1 << bits) - 1))) return 1; + // No more fractional bits to check + bits = 0; + break; + } + } + + // Check the remaining fractional bits in the high - order part of the mantissa + if (bits && bits <= __FLOATL_MANT_HIGH_BITS__) + { + if ((num.mantissa & ((1 << bits) - 1))) return 1; + } + } + + return 0; +} + +/** + * \brief Get the character value of the lowest - order digit of the integer part of a 'floatl' number. + * \param[in] num: The 'floatl' number from which to extract the lowest - order digit of the integer part. + * \return A character representing the lowest - order digit of the integer part of the 'floatl' number. + * + * This function calculates the lowest - order digit of the integer part of a 'floatl' number. + * It first calculates the exponent value relative to the mid - value of the exponent range. + * Then, depending on the exponent value, it either returns '0', '1', or calculates the digit + * through one of two methods (commented out in the code). The current method involves + * handling the mantissa parts of the 'floatl' number and performing modular arithmetic + * to obtain the lowest - order digit. + */ +static char gChar(floatl num) +{ + // An array used to handle the last - digit pattern for powers of 2 + const static char bitEnd[4] = {2,4,8,6}; + // Calculate the actual exponent value + int32_t exp = ((int)num.exponent) - __FLOATL_EXP_MID_VALUE__; + uint32_t c = 0; + + // If the exponent is 0, the lowest - order digit of the integer part is 1 + if (exp == 0) return '1'; + // If the exponent is negative, the integer part is 0 + else if (exp < 0) return '0'; + +#if 0 // This block is commented out. It calculates the result by considering each bit + // Iterate over each bit of the mantissa + for (int i = 0; i < __FLOATL_MANT_BITS__; i++) + { + // Calculate the position relative to the exponent + int index = i - __FLOATL_MANT_BITS__ + exp; + if (index >= 0) + { + // Determine the part of the mantissa array and the bit position + int part = i / 32; + int bit = i % 32; + // Get the appropriate part of the mantissa + uint32_t m = part >= __FLOATL_MANT_PARTS__ ? num.mantissa : num.mantissas[part]; + // Check if the bit is set + if ((m >> bit) & 1) + { + // Add the corresponding value to the accumulator + c += ((index > 0) ? bitEnd[(index - 1) % 4] : 1); + } + } + } + // Add the value corresponding to the exponent + c += ((exp > 0) ? bitEnd[(exp - 1) % 4] : 1); + // Get the last digit and convert it to a character + c = ((unsigned char)c) % 10 + '0'; +#else // This block is the current method, calculating the result by considering u32 parts + // Add the hidden bit to the high - order part of the mantissa + uint32_t hi = (uint32_t)num.mantissa | (1 << __FLOATL_MANT_HIGH_BITS__); + + // If the exponent is less than or equal to the number of high - order mantissa bits + if (exp <= __FLOATL_MANT_HIGH_BITS__) + { + // Calculate the contribution of the high - order mantissa to the last digit + c += ((hi >> (__FLOATL_MANT_HIGH_BITS__ - exp)) % 10); + } + // If the exponent is greater than the number of high - order mantissa bits + else + { + // Determine the bias based on the exponent + char bias = bitEnd[(exp - __FLOATL_MANT_HIGH_BITS__ - 1) % 4]; + // Calculate the number of remaining bits + int bits = exp - __FLOATL_MANT_HIGH_BITS__; + + // Calculate the contribution of the high - order mantissa with the bias + c += ((hi * bias) % 10); + // Iterate over the mantissa array parts + for (int i = __FLOATL_MANT_PARTS__ - 1; i >= 0 && bits > 0; i--, bits -= 32) + { + if (bits > 32) + // Calculate the contribution of the current mantissa part with the bias + c += ((num.mantissas[i] * bias) % 10); + else + // Calculate the contribution of the relevant bits of the current mantissa part + c += ((num.mantissas[i] >> (32 - bits)) % 10); + } + } + // Get the last digit and convert it to a character + c = c % 10 + '0'; +#endif + + return (char)c; +} + +/** + * \brief Reverse a string of a specified length. + * \param[in,out] buffer: A pointer to the character array (string) to be reversed. + * \param[in] len: The length of the string to be reversed. + * + * This function takes a character array and its length as input. It swaps the characters + * from the start and the end of the string towards the middle, effectively reversing the string. + */ +static void reverse(char *buffer, int len) +{ + // Iterate over the first half of the string + for (int i = 0; i < len / 2; i++) + { + // Store the current character in a temporary variable + char tc = buffer[i]; + // Swap the current character with the corresponding character from the end + buffer[i] = buffer[len - 1 - i]; + buffer[len - 1 - i] = tc; + } +} + +/** + * \brief Get the decimal character of the lowest - order digit of the integer part of a 'floatl' number + * and update the 'floatl' number. + * \param[in,out] num: A pointer to the 'floatl' number. The number will be updated after the operation. + * \return The character representing the lowest - order digit of the integer part of the 'floatl' number. + * If the integer part is 0, it returns 0. + * + * This function first checks if the integer part of the 'floatl' number is non - zero using the LT1 function. + * If the integer part is non - zero, it gets the lowest - order digit character using the gChar function. + * Then it divides the 'floatl' number by 10 to prepare for the next digit extraction. + */ +static char floatlIntLowChar(floatl *num) +{ + char c = 0; + + // Check if the integer part of the 'floatl' number is non - zero + if (LT1(*num)) // >= 1, the integer part is not 0 + { + // Get the character of the lowest - order digit of the integer part + c = gChar(*num); + // Divide the 'floatl' number by 10 to move to the next digit + *num = floatl_div(*num, floatl_from_f(10.0)); + } + + return c; +} + +/** + * \brief Get the decimal character of the highest - order digit of the fractional part of a 'floatl' number + * and update the 'floatl' number. + * \param[in,out] num: A pointer to the 'floatl' number. The number will be updated after the operation. + * \return The character representing the highest - order digit of the fractional part of the 'floatl' number. + * If the fractional part is 0, it returns 0. + * + * This function first checks if the fractional part of the 'floatl' number is non - zero using the ST1 function. + * If the fractional part is non - zero, it multiplies the 'floatl' number by 10. Then it gets the highest - order + * digit character of the new number using the gChar function. Finally, it updates the original 'floatl' number. + */ +static char floatlDitHighChar(floatl *num) +{ + char c = 0; + floatl temp = *num; + + // Check if the fractional part of the 'floatl' number is non - zero + if (ST1(temp)) // The decimal part is not 0 + { + // Multiply the 'floatl' number by 10 to get the next digit + temp = floatl_mul(temp, floatl_from_f(10.0)); + // Get the character of the highest - order digit of the new number + c = gChar(temp); + // Update the original 'floatl' number + *num = temp; + } + + return c; +} + +/** + * \brief Perform carry addition on a decimal string. + * \param[in] begin: A pointer to the start of the string. + * \param[in] end: A pointer to the end of the string. + * \param[in] format: A format character used to determine if a specific format marker is reached. + * \return If an exception occurs, returns a pointer to the abnormal character; if the carry is completed, returns NULL; + * if the format marker is reached, returns a pointer to the format marker. + * + * This function traverses the string from the end to the beginning, handling the carry situation of decimal numbers. + * It skips the decimal point, continues to carry forward when encountering '9', and completes the carry when encountering a space or a valid digit. + */ +static char* floatl_carry_add(char *begin, char *end, char format) +{ + // Start traversing from the end of the string + char *s = end; + for (; s >= begin; s--) + { + // If the format character is encountered, return a pointer to this character + if (*s == format) return s; + // Skip the decimal point + if (*s == '.') continue; + // If the current character is '9', set it to '0' and continue to carry forward + else if (*s == '9') + { + *s = '0'; + continue; + } + // If the current character is a space, set it to '1' to indicate the completion of the carry + else if (*s == ' ') + { + *s = '1'; + return NULL; + } + // If the current character is a digit between '0' and '9', increment it by 1 to complete the carry + else if (*s >= '0' && *s < '9') + { + (*s)++; + return NULL; + } + // If an abnormal character is encountered, return a pointer to this character + else return s; + } + + // If the carry is not completed after traversing the entire string, return s + 1 + return s + 1; +} + +/** + * \brief Perform borrow subtraction on a decimal string. + * \param[in] begin: A pointer to the start of the string. + * \param[in] end: A pointer to the end of the string. + * \param[in] format: A format character used to determine if a specific format marker is reached. + * \return If an exception occurs, returns a pointer to the abnormal character; if the borrow is completed, returns NULL; + * if the format marker is reached, returns a pointer to the format marker. + * + * This function traverses the string from the end to the beginning, handling the borrow situation of decimal numbers. + * It skips the decimal point, continues to borrow forward when encountering '0', and completes the borrow when encountering a space or a valid digit. + */ +static char* floatl_carry_sub(char *begin, char *end, char format) +{ + // Start traversing from the end of the string + char *s = end; + for (; s >= begin; s--) + { + // If the format character is encountered, return a pointer to this character + if (*s == format) return s; + // Skip the decimal point + if (*s == '.') continue; + // If the current character is '0', set it to '9' and continue to borrow forward + else if (*s == '0') + { + *s = '9'; + continue; + } + // If the current character is a space, set it to '9' to indicate the completion of the borrow + else if (*s == ' ') + { + *s = '9'; + return NULL; + } + // If the current character is a digit between '1' and '9', decrement it by 1 to complete the borrow + else if (*s > '0' && *s <= '9') + { + (*s)--; + return NULL; + } + // If an abnormal character is encountered, return a pointer to this character + else return s; + } + + // If the borrow is not completed after traversing the entire string, return s + 1 + return s + 1; +} + +/** + * \brief Perform carry addition on a hexadecimal string. + * \param[in] begin: A pointer to the start of the string. + * \param[in] end: A pointer to the end of the string. + * \param[in] format: A format character used to control the case of hexadecimal letters. + * \return If an exception occurs, returns a pointer to the abnormal character; if the carry is completed, returns NULL. + * + * This function traverses the string from the end to the beginning, handling the carry situation of hexadecimal numbers. + * It skips the decimal point, continues to carry forward when encountering 'F' or 'f', and completes the carry when encountering a space or a valid hexadecimal character. + */ +static char* floatl_carry_add_h(char *begin, char *end, char format) +{ + // Start traversing from the end of the string + char *s = end; + for (; s >= begin; s--) + { + // Skip the decimal point + if (*s == '.') continue; + // If the current character is 'F' or 'f', set it to '0' and continue to carry forward + else if (*s == 'F' || *s == 'f') + { + *s = '0'; + continue; + } + // If the current character is a space, set it to '1' to indicate the completion of the carry + else if (*s == ' ') + { + *s = '1'; + return NULL; + } + // If the current character is '9', convert it to 'A' or 'a' according to the format + else if (*s == '9') + { + *s = format ? 'A' : 'a'; + return NULL; + } + // If the current character is a valid hexadecimal character (digit or letter), increment it by 1 to complete the carry + else if ((*s >= '0' && *s < '9') || + (*s >= 'A' && *s < 'F') || + (*s >= 'a' && *s < 'f')) + { + (*s)++; + return NULL; + } + // If an abnormal character is encountered, return a pointer to this character + else return s; + } + + // If the carry is not completed after traversing the entire string, return s + 1 + return s + 1; +} + +/** + * \brief Extract a 4 - bit hexadecimal digit from the mantissa of a 'floatl' number at a specified index. + * \param[in] num: The 'floatl' number from which to extract the hexadecimal digit. + * \param[in] index: The index indicating the position of the 4 - bit group in the mantissa. + * \return The 4 - bit hexadecimal digit (0 - 15) if valid, - 1 if the index is out of range. + * + * This function extracts a 4 - bit hexadecimal digit from the mantissa of a 'floatl' number at the given index. + * It first calculates the bit position within the mantissa based on the index. Then it extracts the relevant bits + * from the appropriate part of the mantissa. If there are insufficient bits in the current part, it may pick up + * bits from the next part. + */ +static char floatl_mant_hex(floatl num, unsigned int index) +{ + // Calculate the starting bit position of the 4 - bit group + int bbit = __FLOATL_MANT_BITS__ - 4 - index * 4; + // Determine the part of the mantissa array where the bit is located + int part = bbit / 32; + // Determine the bit position within the part + int bit = bbit % 32; + char c = 0; + + // If the bit position is negative, the index is out of range + if (bbit < 0) return -1; + + if (part < __FLOATL_MANT_PARTS__) + { + // Extract the 4 - bit group from the current part of the mantissa + c = (num.mantissas[part] >> bit) & 0xF; + + /* If there are insufficient bits in the current part, pick up bits from the next part */ + if (bit > 28) + { + if (part == __FLOATL_MANT_PARTS__ - 1) + // If it's the last part, pick up bits from the high - order mantissa + c |= ((num.mantissa << (32 - bit)) & 0xF); + else + // Otherwise, pick up bits from the next part of the mantissa array + c |= ((num.mantissas[part + 1] << (32 - bit)) & 0xF); + } + } + else + // If the bit is in the high - order mantissa, extract it directly + c = (num.mantissa >> bit) & 0xF; + + return c; +} + +/** + * \brief Convert a 'floatl' number to a string in the %f format. + * \param[in] num: The 'floatl' number to be converted. + * \param[out] buffer: A pointer to the character buffer where the converted string will be stored. + * \param[in] size: The size of the buffer. + * \param[in] flags: Formatting flags that control the output appearance, such as left - alignment, zero - padding, etc. + * \param[in] width: The minimum width of the output string. + * \param[in] precision: The number of digits after the decimal point. + * \return The length of the converted string. + * + * This function converts a 'floatl' number to a string in the %f format. It first extracts the integer and fractional parts of the number. + * Then it handles the sign prefix, performs right - or left - alignment based on the flags, and rounds the result if necessary. + */ +static int floatl_convert_f(floatl num, char *buffer, uint32_t size, uint32_t flags, uint32_t width, uint32_t precision) +{ + char c = 0; + int length = 0; + // Maximum available space in the buffer (excluding the null terminator) + uint32_t max = size - 1; + floatl temp; + char prefix[2] = {0, 0}; + uint32_t prelen = 0; + // Length of the fractional part (including the decimal point if precision > 0) + uint32_t postlen = (precision > 0) ? precision + 1 : 0; + + /* Convert the integer part */ + temp = num; + // Extract digits of the integer part from the lowest to the highest + while ((c = floatlIntLowChar(&temp)) > 0) PRINT_CHAR(c); + + /* The integer part is 0 */ + if (length == 0) PRINT_CHAR('0'); + + /* Handle the sign prefix */ + if (num.sign) prefix[prelen++] = '-'; // Append negative sign + else if (flags & FLAGS_PLUS) prefix[prelen++] = '+'; + + /* Right - alignment */ + if (!((flags & FLAGS_LEFT)) && (flags & FLAGS_ZEROPAD)) + // Pad with zeros if right - aligned and zero - padding is enabled + while (length + prelen + postlen < width) PRINT_CHAR('0'); + // Print the sign prefix + while (prelen > 0) PRINT_CHAR(prefix[--prelen]); + if (!((flags & FLAGS_LEFT)) && !(flags & FLAGS_ZEROPAD)) + // Pad with spaces if right - aligned and zero - padding is disabled + while (length + postlen < width) PRINT_CHAR(' '); + + /* Reverse the integer part */ + reverse(buffer, length); + + /* Convert the fractional part */ + if (precision > 0) + { + /* Decimal point */ + PRINT_CHAR('.'); + + /* Fractional part */ + temp = num; + // Extract digits of the fractional part from the highest to the lowest + while (precision && (c = floatlDitHighChar(&temp)) > 0) { PRINT_CHAR(c); precision--; } + + /* Format alignment */ + // Pad with zeros if the fractional part is shorter than the specified precision + while (precision--) PRINT_CHAR('0'); + } + else + { + temp = num; + c = '0'; + } + + /* If the next digit is valid, continue to calculate the next digit */ + if (c > 0) + { + c = floatlDitHighChar(&temp); + if (c >= '5') + { + char *begin = buffer; + char *end = &buffer[length - 1]; + char *move = NULL; + if (*begin == '+' || *begin == '-') begin++; + + // Perform carry addition for rounding + move = floatl_carry_add(begin, end, 0); + if (move) + { + if (move > begin) + { + *(move - 1) = *move; + } + else + { + PRINT_CHAR('0'); + memmove(move + 1, move, end - move + 1); + } + *move = '1'; + } + } + } + + /* Left - alignment */ + if (flags & FLAGS_LEFT) + // Pad with spaces if left - aligned + while (length < width) PRINT_CHAR(' '); + + buffer[length] = 0; + + return length; +} + +/** + * \brief Convert a 'floatl' number to a string in the %a format. + * \param[in] num: The 'floatl' number to be converted. + * \param[out] buffer: A pointer to the character buffer where the converted string will be stored. + * \param[in] size: The size of the buffer. + * \param[in] flags: Formatting flags that control the output appearance, such as case, left - alignment, etc. + * \param[in] width: The minimum width of the output string. + * \param[in] precision: The number of hexadecimal digits after the decimal point. + * \return The length of the converted string, or - 2 if there is not enough space for the exponent part. + * + * This function converts a 'floatl' number to a string in the %a format, which represents the number in hexadecimal + * floating - point notation. It first converts the exponent part and stores it at the end of the buffer. Then it + * handles the integer and fractional parts, taking into account formatting flags such as sign, alignment, and case. + * Finally, it rounds the result if necessary and moves the exponent part to the appropriate position. + */ +static int floatl_convert_a(floatl num, char *buffer, uint32_t size, uint32_t flags, uint32_t width, uint32_t precision) +{ + char c = 0; + int length = 0; + // Maximum available space in the buffer (excluding the null terminator) + uint32_t max = size - 1; + floatl temp; + // Pointer to the position where the exponent part will be stored + char *expBase = buffer + size; + char prefix[2] = {0, 0}; + uint32_t prelen = 0; + uint32_t postlen = 0; + // Calculate the actual exponent value + int32_t exp = ((int)num.exponent) - __FLOATL_EXP_MID_VALUE__; + // Get the hexadecimal digit for rounding + char carry = floatl_mant_hex(num, precision); + + /* Convert the exponent part and store it at the end of the buffer */ + if (exp == 0) *(--expBase) = '0'; + else + { + int32_t texp = exp; + if (texp < 0) texp = -texp; + // Convert the exponent to decimal digits and store them in reverse order + for ( ; texp != 0; texp /= 10) + { + c = texp % 10 + '0'; + *(--expBase) = c; + if (expBase < buffer + 2) return -2; + } + } + + /* Calculate the remaining length after the integer part */ + postlen = ((precision > 0) ? precision + 1 : 0) + (buffer + size - expBase) + 2; // .d + p+/- + e + + /* Integer part */ + temp = num; + if (temp.exponent == 0) PRINT_CHAR('0'); + else PRINT_CHAR('1'); + // Print 'X' or 'x' based on the case flag + PRINT_CHAR((flags & FLAGS_CASE) ? 'X' : 'x'); + PRINT_CHAR('0'); + + /* Handle the sign prefix */ + if (num.sign) prefix[prelen++] = '-'; // Append negative sign + else if (flags & FLAGS_PLUS) prefix[prelen++] = '+'; + + /* Right - alignment */ + if (!((flags & FLAGS_LEFT)) && (flags & FLAGS_ZEROPAD)) + // Pad with zeros if right - aligned and zero - padding is enabled + while (length + prelen + postlen < width) PRINT_CHAR('0'); + // Print the sign prefix + while (prelen > 0) PRINT_CHAR(prefix[--prelen]); + if (!((flags & FLAGS_LEFT)) && !(flags & FLAGS_ZEROPAD)) + // Pad with spaces if right - aligned and zero - padding is disabled + while (length + postlen < width) PRINT_CHAR(' '); + + /* Reverse the integer part */ + reverse(buffer, length); + + /* Convert the fractional part */ + if (precision > 0) + { + /* Decimal point */ + PRINT_CHAR('.'); + + /* Fractional part */ + temp = num; + temp.sign = 0; + if (floatl_int_cmp(temp, __FLOATL_CONST_0__) == 0) + { + PRINT_CHAR('0'); + precision--; + } + else + { + int index = 0; + // Extract and print hexadecimal digits of the fractional part + while (precision) + { + c = floatl_mant_hex(num, index); + if (c < 0) break; + + if (c < 10) c = c + '0'; + else c = (c - 10) + ((flags & FLAGS_CASE) ? 'A' : 'a'); + PRINT_CHAR(c); + + precision--; + index++; + } + } + + /* Format alignment */ + // Pad with zeros if the fractional part is shorter than the specified precision + while (precision--) PRINT_CHAR('0'); + } + + // Rounding: If the carry digit is greater than 8, perform carry addition + if (carry > 8) + { + char *begin = buffer; + char *end = &buffer[length - 1]; + if (*begin == '+' || *begin == '-') begin++; + floatl_carry_add_h(begin, end, (flags & FLAGS_CASE)); + } + + /* Move the exponent part to the appropriate position */ + // Print 'P' or 'p' based on the case flag + PRINT_CHAR((flags & FLAGS_CASE) ? 'P' : 'p'); + // Print the sign of the exponent + PRINT_CHAR(exp < 0 ? '-' : '+'); + // Print the exponent digits + while (expBase < buffer + size) PRINT_CHAR(*(expBase++)); + + /* Left - alignment */ + if (flags & FLAGS_LEFT) + // Pad with spaces if left - aligned + while (length < width) PRINT_CHAR(' '); + + buffer[length] = 0; + + return length; +} + +/** + * \brief Convert a 'floatl' number to a string in the %e format. + * \param[in] num: The 'floatl' number to be converted. + * \param[out] buffer: A pointer to the character buffer where the converted string will be stored. + * \param[in] size: The size of the buffer. + * \param[in] flags: Formatting flags that control the output appearance, such as case, left - alignment, etc. + * \param[in] width: The minimum width of the output string. + * \param[in] precision: The number of digits after the decimal point. + * \return The length of the converted string, or - 2 if there is not enough space for the exponent part. + * + * This function converts a 'floatl' number to a string in the %e format, which represents the number in scientific notation. + * It first extracts the integer and fractional parts of the number, calculates the exponent, and stores the exponent digits at the end of the buffer. + * Then it handles the sign prefix, performs right - or left - alignment based on the flags, and rounds the result if necessary. + */ +static int floatl_convert_e(floatl num, char *buffer, uint32_t size, uint32_t flags, uint32_t width, uint32_t precision) +{ + char c = 0; + int length = 0; + // Maximum available space in the buffer (excluding the null terminator) + uint32_t max = size - 1; + floatl temp; + // Pointer to the position where the exponent part will be stored + char *expBase = buffer + size; + char prefix[2] = {0, 0}; + uint32_t prelen = 0; + uint32_t postlen = 0; + int offset = 0; + int32_t exp = 0; + char *point = NULL; + + // Buffer to store digits, with extra space for integer and precision digits + char buf[precision + 2]; + FL_STACK dstack = {buf, sizeof(buf), 0, 0}; + + /* Convert the integer part and push digits onto the stack */ + temp = num; + while ((c = floatlIntLowChar(&temp)) > 0) + { + fl_stack_push(&dstack, c); + offset++; + } + + /* Calculate the exponent of the number */ + temp = num; + if (offset > 0) + { + // If there are integer digits, process the fractional part and set the exponent + while ((c = floatlDitHighChar(&temp)) > 0) fl_stack_push_h(&dstack, c); + exp = offset - 1; + } + else + { + if (num.exponent == 0) exp = 0; + else + { + // If there are no integer digits, find the first non - zero fractional digit and set the exponent + while ((c = floatlDitHighChar(&temp)) > 0) + { + offset++; + + if (c != '0') + { + fl_stack_push_h(&dstack, c); + while (dstack.size < dstack.capacity && (c = floatlDitHighChar(&temp)) > 0) fl_stack_push_h(&dstack, c); + exp = -offset; + break; + } + } + } + } + // Pad the stack with zeros if necessary + while (dstack.size < dstack.capacity) fl_stack_push_h(&dstack, '0'); + + // Pop the first digit and print it + fl_stack_pop(&dstack, &c); + PRINT_CHAR(c); + + /* Convert the exponent part and store it at the end of the buffer */ + if (exp == 0) *(--expBase) = '0'; + else + { + int32_t texp = exp; + if (texp < 0) texp = -texp; + // Convert the exponent to decimal digits and store them in reverse order + for ( ; texp != 0; texp /= 10) + { + c = texp % 10 + '0'; + *(--expBase) = c; + if (expBase < buffer + 2) return -2; + } + } + // Ensure the exponent part has at least three digits + while (buffer + size - expBase < 3) *(--expBase) = '0'; + + /* Calculate the remaining length after the integer part */ + postlen = ((precision > 0) ? precision + 1 : 0) + (buffer + size - expBase) + 2; // .d + e+/- + e + + /* Handle the sign prefix */ + if (num.sign) prefix[prelen++] = '-'; // Append negative sign + else if (flags & FLAGS_PLUS) prefix[prelen++] = '+'; + + /* Right - alignment */ + if (!((flags & FLAGS_LEFT)) && (flags & FLAGS_ZEROPAD)) + // Pad with zeros if right - aligned and zero - padding is enabled + while (length + prelen + postlen < width) PRINT_CHAR('0'); + // Print the sign prefix + while (prelen > 0) PRINT_CHAR(prefix[--prelen]); + if (!((flags & FLAGS_LEFT)) && !(flags & FLAGS_ZEROPAD)) + // Pad with spaces if right - aligned and zero - padding is disabled + while (length + postlen < width) PRINT_CHAR(' '); + + /* Reverse the integer part */ + reverse(buffer, length); + + if (precision > 0) + { + /* Decimal point */ + PRINT_CHAR('.'); + point = &buffer[length - 1]; + + // Pop digits from the stack and print them as the fractional part + while (precision && fl_stack_pop(&dstack, &c)) { PRINT_CHAR(c); precision--; } + } + + /* Check if rounding is needed */ + if (dstack.size > 0) + { + fl_stack_pop(&dstack, &c); + + // If the next digit is 5 or greater, perform rounding + if (c >= '5') + { + char *move = NULL; + + // Determine if a carry is needed in the fractional part + if (point) + { + if (floatl_carry_add(point + 1, &buffer[length - 1], '.')) move = point - 1; + } + else move = &buffer[length - 1]; + + // If a carry is needed in the integer part + if (move) + { + // If the integer digit can be incremented + if (*move >= '0' && *move < '9') (*move)++; + // If the integer digit is 9 and needs to be carried over + else + { + // Set the integer digit to 1 + *move = '1'; + + // Increment the exponent part + if (exp >= 0) move = floatl_carry_add(expBase, buffer + size - 1, 0); + else move = floatl_carry_sub(expBase, buffer + size - 1, 0); + + // If the exponent part needs to be carried over + if (move) + { + if (move <= (buffer + length + 2)) return -2; + *(--expBase) = '1'; + } + + // Increment the exponent value + exp++; + } + } + } + } + + /* Move the exponent part to the appropriate position */ + // Print 'E' or 'e' based on the case flag + PRINT_CHAR((flags & FLAGS_CASE) ? 'E' : 'e'); + // Print the sign of the exponent + PRINT_CHAR(exp < 0 ? '-' : '+'); + // Print the exponent digits + while (expBase < buffer + size) PRINT_CHAR(*(expBase++)); + + /* Left - alignment */ + if (flags & FLAGS_LEFT) + // Pad with spaces if left - aligned + while (length < width) PRINT_CHAR(' '); + + buffer[length] = 0; + + return length; +} + +/** + * \brief Converts a 'floatl' number to a string. + * + * This function takes a 'floatl' number and converts it into a string representation + * according to a printf-like format string. The resulting string is stored in the provided buffer. + * + * \param[in] a: The 'floatl' number to be converted. + * \param[out] buffer: A pointer to the buffer where the resulting string will be stored. + * The buffer should be large enough to hold the entire string representation. + * \param[in] size: The size of the buffer, indicating the maximum number of characters it can hold. + * \param[in] format: A printf-like format string, structured as [flags][width][type]. + * Flags can be '0' (zero-padding), '-' (left-alignment), '+' (force sign), + * ' ' (space for positive numbers), '#' (alternate form). + * Width is a decimal number specifying the minimum width of the output. + * Type can be 'a' 'A' 'e' 'E' 'f' 'F' 'g' 'G', determining the output format. + * \return The length of the successfully converted string. + * Returns 0 if the conversion is invalid. + * Returns -1 if the 'buffer' pointer is NULL. + * Returns -2 if the 'size' of the buffer is too small. + * Returns -3 if the 'format' pointer is NULL. + */ +int floatl_print(floatl a, char *buffer, uint32_t size, const char *format) +{ + int length = 0; + // Flags used to control the formatting options of the output + uint32_t flags = 0; + // Minimum width of the output string + uint32_t width = 0; + // Number of digits after the decimal point, default value is 6 + uint32_t precision = 6; + // Maximum available space in the buffer, excluding the null terminator + uint32_t max = size - 1; + + // Check if the buffer pointer is NULL. If so, return -1 indicating an error. + if (!buffer) return -1; + // Check if the buffer size is less than 2. If so, return -2 as it's too small to hold a valid string. + if (size < 2) return -2; + // Check if the format pointer is NULL. If so, return -3 indicating an error. + if (!format) return -3; + + // Skip the '%' character if it's the first character in the format string. + if (*format == '%') format++; + + // Parse the format string character by character + for (; *format; format++) + { + // If the length of the converted string is already greater than 0, break the loop. + if (length > 0) break; + + // Parse the formatting flags in the format string + while (1) + { + if (*format == '0') + { + // Set the zero-padding flag + flags |= FLAGS_ZEROPAD; + format++; + } + else if (*format == '-') + { + // Set the left-alignment flag + flags |= FLAGS_LEFT; + format++; + } + else if (*format == '+') + { + // Set the force sign flag + flags |= FLAGS_PLUS; + format++; + } + else if (*format == ' ') + { + // Set the space for positive numbers flag + flags |= FLAGS_SPACE; + format++; + } + else if (*format == '#') + { + // Set the alternate form flag + flags |= FLAGS_HASH; + format++; + } + else + { + // Exit the loop if no more flags are found + break; + } + } + + /* Convert the width specified in the format string */ + // Parse the characters representing the width in the format string + while ((*format >= '0') && (*format <= '9')) + { + // Convert the digit characters to an integer and update the width value + width = width * 10U + (unsigned int)(*format++ - '0'); + } + // Check if the specified width exceeds the available buffer space. If so, return -1. + if (width > max) return -1; + + // Check if the precision is specified in the format string + if (*format == '.') + { + // Reset the precision value + precision = 0; + format++; + // Parse the characters representing the precision in the format string + while ((*format >= '0') && (*format <= '9')) + { + // Convert the digit characters to an integer and update the precision value + precision = precision * 10U + (unsigned int)(*format++ - '0'); + } + } + // Check if the specified precision exceeds the available buffer space (minus 2 for possible sign and decimal point). If so, return -1. + if (precision > max - 2) return -1; + + /* Distribute the format based on the type specifier */ + // Determine the appropriate conversion function according to the type specifier in the format string + switch (*format) + { + case 'A': + // Set the case flag for uppercase output + flags |= FLAGS_CASE; + case 'a': // Floating-point number in hexadecimal and [P-] notation + { + // Call the function to convert the number to hexadecimal floating-point format + length = floatl_convert_a(a, buffer, size, flags, width, precision); + } + break; + case 'E': + // Set the case flag for uppercase output + flags |= FLAGS_CASE; + case 'e': // Floating-point number in exponential [e-] notation + { + // Call the function to convert the number to exponential floating-point format + length = floatl_convert_e(a, buffer, size, flags, width, precision); + } + break; + case 'G': + case 'g': // Floating-point number, without displaying meaningless zeros + case 'F': + case 'f': // Floating-point number + { + // Call the function to convert the number to regular floating-point format + length = floatl_convert_f(a, buffer, size, flags, width, precision); + } + break; + default: + // Return 0 if the type specifier is invalid + return 0; + } + } + + // Add a null terminator to the end of the converted string + buffer[length] = 0; + + // Return the length of the converted string + return length; +} diff --git a/source/07_math/floatl.h b/source/07_math/floatl.h new file mode 100644 index 0000000..a21440c --- /dev/null +++ b/source/07_math/floatl.h @@ -0,0 +1,174 @@ + +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file floatl.h + * \unit floatl + * \brief This is a simple large float number calculate module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __floatl_H +#define __floatl_H + +#include +#include +#include +#include +#include +#include "floatl_cfg.h" + +/* Version infomation */ + +#define FLOATL_V_MAJOR 1 +#define FLOATL_V_MINOR 0 +#define FLOATL_V_PATCH 0 + +/** + * \brief Common constant definitions + */ + +#define FLOATL_INF __FLOATL_INF__ +#define FLOATL_NAN __FLOATL_NAN__ +#define FLOATL_CONST_0 __FLOATL_CONST_0__ +#define FLOATL_CONST_1 __FLOATL_CONST_1__ +#define FLOATL_CONST_10 __FLOATL_CONST_1e1__ +#define FLOATL_CONST_100 __FLOATL_CONST_1e2__ +#define FLOATL_CONST_1000 __FLOATL_CONST_1e3__ +#define FLOATL_CONST_1e0 __FLOATL_CONST_1e0__ +#define FLOATL_CONST_1e1 __FLOATL_CONST_1e1__ +#define FLOATL_CONST_1e2 __FLOATL_CONST_1e2__ +#define FLOATL_CONST_1e3 __FLOATL_CONST_1e3__ +#define FLOATL_CONST_1e4 __FLOATL_CONST_1e4__ +#define FLOATL_CONST_1e5 __FLOATL_CONST_1e5__ +#define FLOATL_CONST_1e6 __FLOATL_CONST_1e6__ +#define FLOATL_CONST_1e7 __FLOATL_CONST_1e7__ +#define FLOATL_CONST_1e8 __FLOATL_CONST_1e8__ +#define FLOATL_CONST_1e9 __FLOATL_CONST_1e9__ +#define FLOATL_CONST_1e10 __FLOATL_CONST_1e10__ +#define FLOATL_CONST_1e11 __FLOATL_CONST_1e11__ +#define FLOATL_CONST_1e12 __FLOATL_CONST_1e12__ +#define FLOATL_CONST_1e13 __FLOATL_CONST_1e13__ +#define FLOATL_CONST_1e14 __FLOATL_CONST_1e14__ +#define FLOATL_CONST_1e15 __FLOATL_CONST_1e15__ + +/** + * \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 `__FLOATL_U16_PARTS__` uint16_t values, allowing for operations on individual 16-bit segments. + * - An array of `__FLOATL_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[__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; + +/** + * \brief floatl large integer api declaration, support for basic addition, subtraction, multiplication, division, etc. + */ + +// Comparison functions +// floatl_eq: Checks if two floatl numbers are equal +// floatl_ne: Checks if two floatl numbers are not equal +// floatl_lt: Checks if the first floatl number is less than the second +// floatl_le: Checks if the first floatl number is less than or equal to the second +// floatl_gt: Checks if the first floatl number is greater than the second +// floatl_ge: Checks if the first floatl number is greater than or equal to the second + +int floatl_eq(floatl a, floatl b); +int floatl_ne(floatl a, floatl b); +int floatl_lt(floatl a, floatl b); +int floatl_le(floatl a, floatl b); +int floatl_gt(floatl a, floatl b); +int floatl_ge(floatl a, floatl b); + +// Arithmetic operation functions +// floatl_add: Performs addition of two floatl numbers, equivalent to the '+' operator +// floatl_sub: Performs subtraction of two floatl numbers, equivalent to the '-' operator +// floatl_mul: Performs multiplication of two floatl numbers, equivalent to the '*' operator +// floatl_div: Performs division of two floatl numbers, equivalent to the '/' operator + +floatl floatl_add(floatl a, floatl b); +floatl floatl_sub(floatl a, floatl b); +floatl floatl_mul(floatl a, floatl b); +floatl floatl_div(floatl a, floatl b); + +// Attribute checking functions +// floatl_sign: Determines the sign of a floatl number (returns 1 for positive, -1 for negative, 0 for zero) +// floatl_isnan: Checks if a floatl number is NaN (Not a Number) +// floatl_isinf: Checks if a floatl number is infinite +// floatl_isnormal: Checks if a floatl number is a normal number (not zero, NaN, or infinite) + +int floatl_sign(floatl a); +int floatl_isnan(floatl a); +int floatl_isinf(floatl a); +int floatl_isnormal(floatl a); + +// Value modification functions +// floatl_abs: Computes the absolute value of a floatl number +// floatl_neg: Computes the negation of a floatl number, equivalent to the unary '-' operator + +floatl floatl_abs(floatl a); +floatl floatl_neg(floatl a); + +// Conversion functions +// floatl_from: Converts a string to a floatl number +// floatl_from_f: Converts a single-precision floating-point number (float) to a floatl number +// floatl_from_d: Converts a double-precision floating-point number (double) to a floatl number + +floatl floatl_from(const char *str); +floatl floatl_from_f(float value); +floatl floatl_from_d(double value); + +// Output function +// Converts a floatl number to a string according to the specified format and stores it in the buffer + +int floatl_print(floatl a, char *buffer, uint32_t size, const char *format); + +/** + * \brief Converts an integer to a 'floatl' number. + * + * This macro provides a convenient way to convert an integer value to a 'floatl' type number. + * It simply calls the 'floatl_from_d' function, which is assumed to be defined elsewhere, + * to perform the actual conversion. + * + * \param[in] value: The integer value to be converted to a 'floatl' number. + * \return The corresponding 'floatl' number initialized with the given integer value. + */ +#define floatl(value) floatl_from_d(value) + +/** + * \brief A macro to convert a 'floatl' number to a string and handle potential conversion errors. + * + * This macro uses the 'floatl_print' function to convert a 'floatl' number 'a' to a string and + * store it in the buffer 'b' with a given buffer size 's' according to the format string 'f'. + * If the conversion is successful (i.e., 'floatl_print' returns a value greater than 0), it returns + * the pointer to the buffer 'b' containing the converted string. Otherwise, it returns the string + * "invalid" to indicate that the conversion was not successful. + * + * \param a: The 'floatl' number to be converted. + * \param b: A pointer to the buffer where the converted string will be stored. + * \param s: The size of the buffer 'b'. + * \param f: A printf-like format string specifying how the 'floatl' number should be formatted. + * \return A pointer to the buffer 'b' if the conversion is successful; otherwise, a pointer to the + * string literal "invalid". + */ +#define floatl_show(a, b, s, f) (floatl_print((a), (b), (s), (f)) > 0 ? (b) : "invalid") + +#endif + diff --git a/source/07_math/floatl_cfg.h b/source/07_math/floatl_cfg.h new file mode 100644 index 0000000..6d3f26c --- /dev/null +++ b/source/07_math/floatl_cfg.h @@ -0,0 +1,779 @@ + +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file floatl_cfg.h + * \unit floatl + * \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 __floatl_cfg_H +#define __floatl_cfg_H + +/* + * With this definition, you can configure the footprint size of an floatl. + * This is a flexible definition that can be extended to larger numbers in addition to the given few size definitions + */ + +/*****************************************************************/ +/* Config start */ +/*****************************************************************/ +// #define FLOATL_USE_64BITS +// #define FLOATL_USE_128BITS +// #define FLOATL_USE_256BITS +#define FLOATL_USE_512BITS +// #define FLOATL_USE_1024BITS +// #define FLOATL_USE_2048BITS +// #define FLOATL_USE_4096BITS +// #define FLOATL_USE_8192BITS + +#if defined(FLOATL_USE_64BITS) +#define __FLOATL_BIT_PARTS__ 64 +#define __FLOATL_U32_PARTS__ 2 +#define __FLOATL_U16_PARTS__ 4 +#define __FLOATL_EXP_BITS__ 11 +#define __FLOATL_MANT_BITS__ 52 +#define __FLOATL_MANT_PARTS__ 1 +#define __FLOATL_MANT_HIGH_BITS__ 20 +#define __FLOATL_EXP_MID_VALUE__ 1023 +#define __FLOATL_EXP_WHL_VALUE__ 2047 +#define __FLOATL2_BIT_PARTS__ 128 +#define __FLOATL2_U32_PARTS__ 4 +#define __FLOATL2_U16_PARTS__ 8 +#define __FLOATL_CONST_0__ (floatl){.u32={0,0,}} +#define __FLOATL_CONST_1__ (floatl){.u32={0,0x3FF00000,}} +#define __FLOATL_CONST_1e0__ (floatl){.u32={0,0x3FF00000,}} +#define __FLOATL_CONST_1e1__ (floatl){.u32={0,0x40240000,}} +#define __FLOATL_CONST_1e2__ (floatl){.u32={0,0x40590000,}} +#define __FLOATL_CONST_1e3__ (floatl){.u32={0,0x408F4000,}} +#define __FLOATL_CONST_1e4__ (floatl){.u32={0,0x40C38800,}} +#define __FLOATL_CONST_1e5__ (floatl){.u32={0,0x40F86A00,}} +#define __FLOATL_CONST_1e6__ (floatl){.u32={0,0x412E8480,}} +#define __FLOATL_CONST_1e7__ (floatl){.u32={0,0x416312D0,}} +#define __FLOATL_CONST_1e8__ (floatl){.u32={0,0x4197D784,}} +#define __FLOATL_CONST_1e9__ (floatl){.u32={0,0x41CDCD65,}} +#define __FLOATL_CONST_1e10__ (floatl){.u32={0x20000000,0x4202A05F,}} +#define __FLOATL_CONST_1e11__ (floatl){.u32={0xE8000000,0x42374876,}} +#define __FLOATL_CONST_1e12__ (floatl){.u32={0xA2000000,0x426D1A94,}} +#define __FLOATL_CONST_1e13__ (floatl){.u32={0xE5400000,0x42A2309C,}} +#define __FLOATL_CONST_1e14__ (floatl){.u32={0x1E900000,0x42D6BCC4,}} +#define __FLOATL_CONST_1e15__ (floatl){.u32={0x26340000,0x430C6BF5,}} +#define __FLOATL_INT_ZERO__ (floatl){.u32={0,0,}} +#define __FLOATL_INF__ (floatl){.u32={0,0x7FF00000,}} +#define __FLOATL_NAN__ (floatl){.u32={0,0xFFF00000,}} +#define __FLOATL_ALL_SIGN__ (floatl){.u32={0,0x80000000,}} +#define __FLOATL_ALL_EXP__ (floatl){.u32={0,0x7FF00000,}} +#define __FLOATL_ALL_MANT__ (floatl){.u32={-1,0x000FFFFF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.u32={-1,0x7FFFFFFF,}} +#define __FLOATL_HIDE_MANT_BIT__ (floatl){.u32={0,0x00100000,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.u32={0,0x00800000,}} +#define __FLOATL_MANT_WHL__ (floatl){.u32={-1,0x001FFFFF,}} +#elif defined(FLOATL_USE_128BITS) +#define __FLOATL_BIT_PARTS__ 128 +#define __FLOATL_U32_PARTS__ 4 +#define __FLOATL_U16_PARTS__ 8 +#define __FLOATL_EXP_BITS__ 13 +#define __FLOATL_MANT_BITS__ 114 +#define __FLOATL_MANT_PARTS__ 3 +#define __FLOATL_MANT_HIGH_BITS__ 18 +#define __FLOATL_EXP_MID_VALUE__ 4095 +#define __FLOATL_EXP_WHL_VALUE__ 8191 +#define __FLOATL2_BIT_PARTS__ 256 +#define __FLOATL2_U32_PARTS__ 8 +#define __FLOATL2_U16_PARTS__ 16 +#define __FLOATL_CONST_0__ (floatl){.u32={0,0,0,0,}} +#define __FLOATL_CONST_1__ (floatl){.u32={0,0,0,0x3FFC0000,}} +#define __FLOATL_CONST_1e0__ (floatl){.u32={0,0,0,0x3FFC0000,}} +#define __FLOATL_CONST_1e1__ (floatl){.u32={0,0,0,0x40090000,}} +#define __FLOATL_CONST_1e2__ (floatl){.u32={0,0,0,0x40164000,}} +#define __FLOATL_CONST_1e3__ (floatl){.u32={0,0,0,0x4023D000,}} +#define __FLOATL_CONST_1e4__ (floatl){.u32={0,0,0,0x4030E200,}} +#define __FLOATL_CONST_1e5__ (floatl){.u32={0,0,0,0x403E1A80,}} +#define __FLOATL_CONST_1e6__ (floatl){.u32={0,0,0,0x404BA120,}} +#define __FLOATL_CONST_1e7__ (floatl){.u32={0,0,0,0x4058C4B4,}} +#define __FLOATL_CONST_1e8__ (floatl){.u32={0,0,0,0x4065F5E1,}} +#define __FLOATL_CONST_1e9__ (floatl){.u32={0,0,0x40000000,0x40737359,}} +#define __FLOATL_CONST_1e10__ (floatl){.u32={0,0,0xC8000000,0x4080A817,}} +#define __FLOATL_CONST_1e11__ (floatl){.u32={0,0,0xBA000000,0x408DD21D,}} +#define __FLOATL_CONST_1e12__ (floatl){.u32={0,0,0x28800000,0x409B46A5,}} +#define __FLOATL_CONST_1e13__ (floatl){.u32={0,0,0x39500000,0x40A88C27,}} +#define __FLOATL_CONST_1e14__ (floatl){.u32={0,0,0x07A40000,0x40B5AF31,}} +#define __FLOATL_CONST_1e15__ (floatl){.u32={0,0,0x498D0000,0x40C31AFD,}} +#define __FLOATL_INT_ZERO__ (floatl){.u32={0,0,0,0,}} +#define __FLOATL_INF__ (floatl){.u32={0,0,0,0x7FFC0000,}} +#define __FLOATL_NAN__ (floatl){.u32={0,0,0,0xFFFC0000,}} +#define __FLOATL_ALL_SIGN__ (floatl){.u32={0,0,0,0x80000000,}} +#define __FLOATL_ALL_EXP__ (floatl){.u32={0,0,0,0x7FFC0000,}} +#define __FLOATL_ALL_MANT__ (floatl){.u32={-1,-1,-1,0x0003FFFF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.u32={-1,-1,-1,0x7FFFFFFF,}} +#define __FLOATL_HIDE_MANT_BIT__ (floatl){.u32={0,0,0,0x00040000,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.u32={0,0,0,0x00200000,}} +#define __FLOATL_MANT_WHL__ (floatl){.u32={-1,-1,-1,0x0007FFFF,}} +#elif defined(FLOATL_USE_256BITS) +#define __FLOATL_BIT_PARTS__ 256 +#define __FLOATL_U32_PARTS__ 8 +#define __FLOATL_U16_PARTS__ 16 +#define __FLOATL_EXP_BITS__ 15 +#define __FLOATL_MANT_BITS__ 240 +#define __FLOATL_MANT_PARTS__ 7 +#define __FLOATL_MANT_HIGH_BITS__ 16 +#define __FLOATL_EXP_MID_VALUE__ 16383 +#define __FLOATL_EXP_WHL_VALUE__ 32767 +#define __FLOATL2_BIT_PARTS__ 512 +#define __FLOATL2_U32_PARTS__ 16 +#define __FLOATL2_U16_PARTS__ 32 +#define __FLOATL_CONST_0__ (floatl){.u32={0,0,0,0,0,0,0,0,}} +#define __FLOATL_CONST_1__ (floatl){.u32={0,0,0,0,0,0,0,0x3FFF0000,}} +#define __FLOATL_CONST_1e0__ (floatl){.u32={0,0,0,0,0,0,0,0x3FFF0000,}} +#define __FLOATL_CONST_1e1__ (floatl){.u32={0,0,0,0,0,0,0,0x40024000,}} +#define __FLOATL_CONST_1e2__ (floatl){.u32={0,0,0,0,0,0,0,0x40059000,}} +#define __FLOATL_CONST_1e3__ (floatl){.u32={0,0,0,0,0,0,0,0x4008F400,}} +#define __FLOATL_CONST_1e4__ (floatl){.u32={0,0,0,0,0,0,0,0x400C3880,}} +#define __FLOATL_CONST_1e5__ (floatl){.u32={0,0,0,0,0,0,0,0x400F86A0,}} +#define __FLOATL_CONST_1e6__ (floatl){.u32={0,0,0,0,0,0,0,0x4012E848,}} +#define __FLOATL_CONST_1e7__ (floatl){.u32={0,0,0,0,0,0,0,0x4016312D,}} +#define __FLOATL_CONST_1e8__ (floatl){.u32={0,0,0,0,0,0,0x40000000,0x40197D78,}} +#define __FLOATL_CONST_1e9__ (floatl){.u32={0,0,0,0,0,0,0x50000000,0x401CDCD6,}} +#define __FLOATL_CONST_1e10__ (floatl){.u32={0,0,0,0,0,0,0xF2000000,0x40202A05,}} +#define __FLOATL_CONST_1e11__ (floatl){.u32={0,0,0,0,0,0,0x6E800000,0x40237487,}} +#define __FLOATL_CONST_1e12__ (floatl){.u32={0,0,0,0,0,0,0x4A200000,0x4026D1A9,}} +#define __FLOATL_CONST_1e13__ (floatl){.u32={0,0,0,0,0,0,0xCE540000,0x402A2309,}} +#define __FLOATL_CONST_1e14__ (floatl){.u32={0,0,0,0,0,0,0x41E90000,0x402D6BCC,}} +#define __FLOATL_CONST_1e15__ (floatl){.u32={0,0,0,0,0,0,0x52634000,0x4030C6BF,}} +#define __FLOATL_INT_ZERO__ (floatl){.u32={0,0,0,0,0,0,0,0,}} +#define __FLOATL_INF__ (floatl){.u32={0,0,0,0,0,0,0,0x7FFF0000,}} +#define __FLOATL_NAN__ (floatl){.u32={0,0,0,0,0,0,0,0xFFFF0000,}} +#define __FLOATL_ALL_SIGN__ (floatl){.u32={0,0,0,0,0,0,0,0x80000000,}} +#define __FLOATL_ALL_EXP__ (floatl){.u32={0,0,0,0,0,0,0,0x7FFF0000,}} +#define __FLOATL_ALL_MANT__ (floatl){.u32={-1,-1,-1,-1,-1,-1,-1,0x0000FFFF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.u32={-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}} +#define __FLOATL_HIDE_MANT_BIT__ (floatl){.u32={0,0,0,0,0,0,0,0x00010000,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.u32={0,0,0,0,0,0,0,0x00080000,}} +#define __FLOATL_MANT_WHL__ (floatl){.u32={-1,-1,-1,-1,-1,-1,-1,0x0001FFFF,}} +#elif defined(FLOATL_USE_512BITS) +#define __FLOATL_BIT_PARTS__ 512 +#define __FLOATL_U32_PARTS__ 16 +#define __FLOATL_U16_PARTS__ 32 +#define __FLOATL_EXP_BITS__ 17 +#define __FLOATL_MANT_BITS__ 494 +#define __FLOATL_MANT_PARTS__ 15 +#define __FLOATL_MANT_HIGH_BITS__ 14 +#define __FLOATL_EXP_MID_VALUE__ 65535 +#define __FLOATL_EXP_WHL_VALUE__ 131071 +#define __FLOATL2_BIT_PARTS__ 1024 +#define __FLOATL2_U32_PARTS__ 32 +#define __FLOATL2_U16_PARTS__ 64 +#define __FLOATL_CONST_0__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}} +#define __FLOATL_CONST_1__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3FFFC000,}} +#define __FLOATL_CONST_1e0__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3FFFC000,}} +#define __FLOATL_CONST_1e1__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x40009000,}} +#define __FLOATL_CONST_1e2__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x40016400,}} +#define __FLOATL_CONST_1e3__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x40023D00,}} +#define __FLOATL_CONST_1e4__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x40030E20,}} +#define __FLOATL_CONST_1e5__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4003E1A8,}} +#define __FLOATL_CONST_1e6__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4004BA12,}} +#define __FLOATL_CONST_1e7__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x40000000,0x40058C4B,}} +#define __FLOATL_CONST_1e8__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x10000000,0x40065F5E,}} +#define __FLOATL_CONST_1e9__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x94000000,0x40073735,}} +#define __FLOATL_CONST_1e10__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7C800000,0x40080A81,}} +#define __FLOATL_CONST_1e11__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xDBA00000,0x4008DD21,}} +#define __FLOATL_CONST_1e12__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x52880000,0x4009B46A,}} +#define __FLOATL_CONST_1e13__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x73950000,0x400A88C2,}} +#define __FLOATL_CONST_1e14__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x107A4000,0x400B5AF3,}} +#define __FLOATL_CONST_1e15__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xD498D000,0x400C31AF,}} +#define __FLOATL_INT_ZERO__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}} +#define __FLOATL_INF__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7FFFC000,}} +#define __FLOATL_NAN__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xFFFFC000,}} +#define __FLOATL_ALL_SIGN__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}} +#define __FLOATL_ALL_EXP__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7FFFC000,}} +#define __FLOATL_ALL_MANT__ (floatl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x00003FFF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}} +#define __FLOATL_HIDE_MANT_BIT__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00004000,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00020000,}} +#define __FLOATL_MANT_WHL__ (floatl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x00007FFF,}} +#elif defined(FLOATL_USE_1024BITS) +#define __FLOATL_BIT_PARTS__ 1024 +#define __FLOATL_U32_PARTS__ 32 +#define __FLOATL_U16_PARTS__ 64 +#define __FLOATL_EXP_BITS__ 19 +#define __FLOATL_MANT_BITS__ 1004 +#define __FLOATL_MANT_PARTS__ 31 +#define __FLOATL_MANT_HIGH_BITS__ 12 +#define __FLOATL_EXP_MID_VALUE__ 262143 +#define __FLOATL_EXP_WHL_VALUE__ 524287 +#define __FLOATL2_BIT_PARTS__ 2048 +#define __FLOATL2_U32_PARTS__ 64 +#define __FLOATL2_U16_PARTS__ 128 +#define __FLOATL_CONST_0__ (floatl){.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,}} +#define __FLOATL_CONST_1__ (floatl){.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,0x3FFFF000,}} +#define __FLOATL_CONST_1e0__ (floatl){.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,0x3FFFF000,}} +#define __FLOATL_CONST_1e1__ (floatl){.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,0x40002400,}} +#define __FLOATL_CONST_1e2__ (floatl){.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,0x40005900,}} +#define __FLOATL_CONST_1e3__ (floatl){.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,0x40008F40,}} +#define __FLOATL_CONST_1e4__ (floatl){.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,0x4000C388,}} +#define __FLOATL_CONST_1e5__ (floatl){.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,0x4000F86A,}} +#define __FLOATL_CONST_1e6__ (floatl){.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,0x80000000,0x40012E84,}} +#define __FLOATL_CONST_1e7__ (floatl){.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,0xD0000000,0x40016312,}} +#define __FLOATL_CONST_1e8__ (floatl){.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,0x84000000,0x400197D7,}} +#define __FLOATL_CONST_1e9__ (floatl){.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,0x65000000,0x4001CDCD,}} +#define __FLOATL_CONST_1e10__ (floatl){.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,0x5F200000,0x400202A0,}} +#define __FLOATL_CONST_1e11__ (floatl){.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,0x76E80000,0x40023748,}} +#define __FLOATL_CONST_1e12__ (floatl){.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,0x94A20000,0x40026D1A,}} +#define __FLOATL_CONST_1e13__ (floatl){.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,0x9CE54000,0x4002A230,}} +#define __FLOATL_CONST_1e14__ (floatl){.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,0xC41E9000,0x4002D6BC,}} +#define __FLOATL_CONST_1e15__ (floatl){.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,0xF5263400,0x40030C6B,}} +#define __FLOATL_INT_ZERO__ (floatl){.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,}} +#define __FLOATL_INF__ (floatl){.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,0x7FFFF000,}} +#define __FLOATL_NAN__ (floatl){.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,0xFFFFF000,}} +#define __FLOATL_ALL_SIGN__ (floatl){.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 __FLOATL_ALL_EXP__ (floatl){.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,0x7FFFF000,}} +#define __FLOATL_ALL_MANT__ (floatl){.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,0x00000FFF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.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 __FLOATL_HIDE_MANT_BIT__ (floatl){.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,0x00001000,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.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,0x00008000,}} +#define __FLOATL_MANT_WHL__ (floatl){.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,0x00001FFF,}} +#elif defined(FLOATL_USE_2048BITS) +#define __FLOATL_BIT_PARTS__ 2048 +#define __FLOATL_U32_PARTS__ 64 +#define __FLOATL_U16_PARTS__ 128 +#define __FLOATL_EXP_BITS__ 21 +#define __FLOATL_MANT_BITS__ 2026 +#define __FLOATL_MANT_PARTS__ 63 +#define __FLOATL_MANT_HIGH_BITS__ 10 +#define __FLOATL_EXP_MID_VALUE__ 1048575 +#define __FLOATL_EXP_WHL_VALUE__ 2097151 +#define __FLOATL2_BIT_PARTS__ 4096 +#define __FLOATL2_U32_PARTS__ 128 +#define __FLOATL2_U16_PARTS__ 256 +#define __FLOATL_CONST_0__ (floatl){.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,}} +#define __FLOATL_CONST_1__ (floatl){.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,0x3FFFFC00,}} +#define __FLOATL_CONST_1e0__ (floatl){.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,0x3FFFFC00,}} +#define __FLOATL_CONST_1e1__ (floatl){.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,0x40000900,}} +#define __FLOATL_CONST_1e2__ (floatl){.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,0x40001640,}} +#define __FLOATL_CONST_1e3__ (floatl){.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,0x400023D0,}} +#define __FLOATL_CONST_1e4__ (floatl){.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,0x400030E2,}} +#define __FLOATL_CONST_1e5__ (floatl){.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,0x80000000,0x40003E1A,}} +#define __FLOATL_CONST_1e6__ (floatl){.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,0x20000000,0x40004BA1,}} +#define __FLOATL_CONST_1e7__ (floatl){.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,0xB4000000,0x400058C4,}} +#define __FLOATL_CONST_1e8__ (floatl){.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,0xE1000000,0x400065F5,}} +#define __FLOATL_CONST_1e9__ (floatl){.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,0x59400000,0x40007373,}} +#define __FLOATL_CONST_1e10__ (floatl){.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,0x17C80000,0x400080A8,}} +#define __FLOATL_CONST_1e11__ (floatl){.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,0x1DBA0000,0x40008DD2,}} +#define __FLOATL_CONST_1e12__ (floatl){.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,0xA5288000,0x40009B46,}} +#define __FLOATL_CONST_1e13__ (floatl){.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,0x27395000,0x4000A88C,}} +#define __FLOATL_CONST_1e14__ (floatl){.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,0x3107A400,0x4000B5AF,}} +#define __FLOATL_CONST_1e15__ (floatl){.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,0xFD498D00,0x4000C31A,}} +#define __FLOATL_INT_ZERO__ (floatl){.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,}} +#define __FLOATL_INF__ (floatl){.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,0x7FFFFC00,}} +#define __FLOATL_NAN__ (floatl){.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,0xFFFFFC00,}} +#define __FLOATL_ALL_SIGN__ (floatl){.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 __FLOATL_ALL_EXP__ (floatl){.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,0x7FFFFC00,}} +#define __FLOATL_ALL_MANT__ (floatl){.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,0x000003FF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.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 __FLOATL_HIDE_MANT_BIT__ (floatl){.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,0x00000400,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.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,0x00002000,}} +#define __FLOATL_MANT_WHL__ (floatl){.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,0x000007FF,}} +#elif defined(FLOATL_USE_4096BITS) +#define __FLOATL_BIT_PARTS__ 4096 +#define __FLOATL_U32_PARTS__ 128 +#define __FLOATL_U16_PARTS__ 256 +#define __FLOATL_EXP_BITS__ 23 +#define __FLOATL_MANT_BITS__ 4072 +#define __FLOATL_MANT_PARTS__ 127 +#define __FLOATL_MANT_HIGH_BITS__ 8 +#define __FLOATL_EXP_MID_VALUE__ 4194303 +#define __FLOATL_EXP_WHL_VALUE__ 8388607 +#define __FLOATL2_BIT_PARTS__ 8192 +#define __FLOATL2_U32_PARTS__ 256 +#define __FLOATL2_U16_PARTS__ 512 +#define __FLOATL_CONST_0__ (floatl){.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,}} +#define __FLOATL_CONST_1__ (floatl){.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,0x3FFFFF00,}} +#define __FLOATL_CONST_1e0__ (floatl){.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,0x3FFFFF00,}} +#define __FLOATL_CONST_1e1__ (floatl){.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,0x40000240,}} +#define __FLOATL_CONST_1e2__ (floatl){.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,0x40000590,}} +#define __FLOATL_CONST_1e3__ (floatl){.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,0x400008F4,}} +#define __FLOATL_CONST_1e4__ (floatl){.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,0x80000000,0x40000C38,}} +#define __FLOATL_CONST_1e5__ (floatl){.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,0xA0000000,0x40000F86,}} +#define __FLOATL_CONST_1e6__ (floatl){.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,0x48000000,0x400012E8,}} +#define __FLOATL_CONST_1e7__ (floatl){.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,0x2D000000,0x40001631,}} +#define __FLOATL_CONST_1e8__ (floatl){.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,0x78400000,0x4000197D,}} +#define __FLOATL_CONST_1e9__ (floatl){.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,0xD6500000,0x40001CDC,}} +#define __FLOATL_CONST_1e10__ (floatl){.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,0x05F20000,0x4000202A,}} +#define __FLOATL_CONST_1e11__ (floatl){.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,0x876E8000,0x40002374,}} +#define __FLOATL_CONST_1e12__ (floatl){.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,0xA94A2000,0x400026D1,}} +#define __FLOATL_CONST_1e13__ (floatl){.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,0x09CE5400,0x40002A23,}} +#define __FLOATL_CONST_1e14__ (floatl){.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,0xCC41E900,0x40002D6B,}} +#define __FLOATL_CONST_1e15__ (floatl){.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,0xBF526340,0x400030C6,}} +#define __FLOATL_INT_ZERO__ (floatl){.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,}} +#define __FLOATL_INF__ (floatl){.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,0x7FFFFF00,}} +#define __FLOATL_NAN__ (floatl){.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,0xFFFFFF00,}} +#define __FLOATL_ALL_SIGN__ (floatl){.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 __FLOATL_ALL_EXP__ (floatl){.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,0x7FFFFF00,}} +#define __FLOATL_ALL_MANT__ (floatl){.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,0x000000FF,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.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 __FLOATL_HIDE_MANT_BIT__ (floatl){.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,0x00000100,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.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,0x00000800,}} +#define __FLOATL_MANT_WHL__ (floatl){.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,0x000001FF,}} +#elif defined(FLOATL_USE_8192BITS) +#define __FLOATL_BIT_PARTS__ 8192 +#define __FLOATL_U32_PARTS__ 256 +#define __FLOATL_U16_PARTS__ 512 +#define __FLOATL_EXP_BITS__ 25 +#define __FLOATL_MANT_BITS__ 8166 +#define __FLOATL_MANT_PARTS__ 255 +#define __FLOATL_MANT_HIGH_BITS__ 6 +#define __FLOATL_EXP_MID_VALUE__ 16777215 +#define __FLOATL_EXP_WHL_VALUE__ 33554431 +#define __FLOATL2_BIT_PARTS__ 16384 +#define __FLOATL2_U32_PARTS__ 512 +#define __FLOATL2_U16_PARTS__ 1024 +#define __FLOATL_CONST_0__ (floatl){.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,}} +#define __FLOATL_CONST_1__ (floatl){.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,0x3FFFFFC0,}} +#define __FLOATL_CONST_1e0__ (floatl){.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,0x3FFFFFC0,}} +#define __FLOATL_CONST_1e1__ (floatl){.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,0x40000090,}} +#define __FLOATL_CONST_1e2__ (floatl){.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,0x40000164,}} +#define __FLOATL_CONST_1e3__ (floatl){.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,0x4000023D,}} +#define __FLOATL_CONST_1e4__ (floatl){.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,0x20000000,0x4000030E,}} +#define __FLOATL_CONST_1e5__ (floatl){.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,0xA8000000,0x400003E1,}} +#define __FLOATL_CONST_1e6__ (floatl){.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,0x12000000,0x400004BA,}} +#define __FLOATL_CONST_1e7__ (floatl){.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,0x4B400000,0x4000058C,}} +#define __FLOATL_CONST_1e8__ (floatl){.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,0x5E100000,0x4000065F,}} +#define __FLOATL_CONST_1e9__ (floatl){.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,0x35940000,0x40000737,}} +#define __FLOATL_CONST_1e10__ (floatl){.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,0x817C8000,0x4000080A,}} +#define __FLOATL_CONST_1e11__ (floatl){.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,0x21DBA000,0x400008DD,}} +#define __FLOATL_CONST_1e12__ (floatl){.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,0x6A528800,0x400009B4,}} +#define __FLOATL_CONST_1e13__ (floatl){.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,0xC2739500,0x40000A88,}} +#define __FLOATL_CONST_1e14__ (floatl){.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,0xF3107A40,0x40000B5A,}} +#define __FLOATL_CONST_1e15__ (floatl){.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,0xAFD498D0,0x40000C31,}} +#define __FLOATL_INT_ZERO__ (floatl){.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,}} +#define __FLOATL_INF__ (floatl){.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,0x7FFFFFC0,}} +#define __FLOATL_NAN__ (floatl){.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,0xFFFFFFC0,}} +#define __FLOATL_ALL_SIGN__ (floatl){.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 __FLOATL_ALL_EXP__ (floatl){.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,0x7FFFFFC0,}} +#define __FLOATL_ALL_MANT__ (floatl){.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,0x0000003F,}} +#define __FLOATL_ALL_EXP_MANT__ (floatl){.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 __FLOATL_HIDE_MANT_BIT__ (floatl){.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,0x00000040,}} +#define __FLOATL_MANT_PLUS_MAX__ (floatl){.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,0x00000200,}} +#define __FLOATL_MANT_WHL__ (floatl){.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,0x0000007F,}} +#endif +/*****************************************************************/ +/* Config end */ +/*****************************************************************/ + +#if 0 +/*----------------------------------------------------------------------------------*/ +/* Generate configuration [START] */ +/*----------------------------------------------------------------------------------*/ + +typedef struct +{ + uint32_t buffer[256]; + + uint32_t FLOATL_BIT_PARTS; // bits + uint32_t FLOATL_U32_PARTS; // FLOATL_BIT_PARTS / 32 ---- FLOATL_BIT_PARTS >> 5 + uint32_t FLOATL_U16_PARTS; // FLOATL_BIT_PARTS / 16 ---- FLOATL_BIT_PARTS >> 4 + uint32_t FLOATL_EXP_BITS; // floatl_cfg_gen_exp(FLOATL_BIT_PARTS) + uint32_t FLOATL_MANT_BITS; // FLOATL_BIT_PARTS - FLOATL_EXP_BITS - 1 + uint32_t FLOATL_MANT_PARTS; // FLOATL_MANT_BITS / 32 ---- FLOATL_MANT_BITS >> 5 + uint32_t FLOATL_MANT_HIGH_BITS; // FLOATL_MANT_BITS % 32 ---- FLOATL_MANT_BITS & 0x1F + uint32_t FLOATL_EXP_MID_VALUE; // 2^(FLOATL_EXP_BITS-1) - 1 + uint32_t FLOATL_EXP_WHL_VALUE; // 2^(FLOATL_EXP_BITS) - 1 + + uint32_t FLOATL2_BIT_PARTS; // FLOATL_BIT_PARTS * 2 + uint32_t FLOATL2_U32_PARTS; // FLOATL2_BIT_PARTS / 32 ---- FLOATL2_BIT_PARTS >> 5 + uint32_t FLOATL2_U16_PARTS; // FLOATL2_BIT_PARTS / 16 ---- FLOATL2_BIT_PARTS >> 4 +} FLINFO; + +typedef struct +{ + uint32_t exp; + char *mantBin; +} FLCSTE; // const pow10(n) + +static FLCSTE fle_list[] = { + {.exp = 0, .mantBin = "0000000000000000000000000000000000000000000000000000"}, + {.exp = 3, .mantBin = "0100000000000000000000000000000000000000000000000000"}, + {.exp = 6, .mantBin = "1001000000000000000000000000000000000000000000000000"}, + {.exp = 9, .mantBin = "1111010000000000000000000000000000000000000000000000"}, + {.exp = 13, .mantBin = "0011100010000000000000000000000000000000000000000000"}, + {.exp = 16, .mantBin = "1000011010100000000000000000000000000000000000000000"}, + {.exp = 19, .mantBin = "1110100001001000000000000000000000000000000000000000"}, + {.exp = 23, .mantBin = "0011000100101101000000000000000000000000000000000000"}, + {.exp = 26, .mantBin = "0111110101111000010000000000000000000000000000000000"}, + {.exp = 29, .mantBin = "1101110011010110010100000000000000000000000000000000"}, + {.exp = 33, .mantBin = "0010101000000101111100100000000000000000000000000000"}, + {.exp = 36, .mantBin = "0111010010000111011011101000000000000000000000000000"}, + {.exp = 39, .mantBin = "1101000110101001010010100010000000000000000000000000"}, + {.exp = 43, .mantBin = "0010001100001001110011100101010000000000000000000000"}, + {.exp = 46, .mantBin = "0110101111001100010000011110100100000000000000000000"}, + {.exp = 49, .mantBin = "1100011010111111010100100110001101000000000000000000"}, +}; + +// e = 2.8625 * log2(bits) + 0.0111 * bits - 6.6730 +uint32_t floatl_cfg_gen_exp(uint32_t bits) +{ + const int y = bits; + int mantissa = 0; + int exponent = 0; + int sign = 1; + + for (int i = y; i > 0; i--) + { + if (log2(i) * 2 < (y - i - 1)) + { + mantissa = i + 1; + break; + } + } + exponent = bits - sign - mantissa; + + // printf("---------------- %d\r\n", bits); + // printf("mantissa %d\r\n", mantissa); + // printf("exponent %d\r\n", exponent); + // printf("sign %d\r\n", sign); + + // printf("high %d\r\n", mantissa & 0x1F); // % 32 + // printf("part %d\r\n", mantissa >> 5); // / 32 + + if (exponent >= 31) return 0; + + return exponent; +} + +void floatl_cfg_const_out(FILE* file, FLINFO *info) +{ + if (!file || !info) return; + + fprintf(file, "(floatl){.u32={"); + for (int i = 0; i < info->FLOATL_U32_PARTS; i++) + { + uint32_t value = info->buffer[i]; + if (value == 0) fprintf(file, "0,"); + else if (value == 0xFFFFFFFF) fprintf(file, "-1,"); + else fprintf(file, "0x%08X,", value); + } + fprintf(file, "}}\n"); +} + +FLINFO *floatl_cfg_set_sign(FLINFO *info, int sign) +{ + if (sign) info->buffer[info->FLOATL_U32_PARTS - 1] |= (1 << 31); + else info->buffer[info->FLOATL_U32_PARTS - 1] &= ~(1 << 31); + return info; +} + +FLINFO *floatl_cfg_set_exp_real(FLINFO *info, uint32_t t) +{ + uint32_t temp = 1; + + temp <<= info->FLOATL_EXP_BITS; + temp -= 1; + + t &= temp; + t <<= (32 - info->FLOATL_EXP_BITS - 1); + + temp <<= (32 - info->FLOATL_EXP_BITS - 1); + + + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~temp); // clear + + info->buffer[info->FLOATL_U32_PARTS - 1] |= t; + + return info; +} + +FLINFO *floatl_cfg_set_exp(FLINFO *info, int32_t e) +{ + return floatl_cfg_set_exp_real(info, e + info->FLOATL_EXP_MID_VALUE); +} + +FLINFO *floatl_cfg_set_mant(FLINFO *info, char *bin) +{ + char *s = bin; + + while (*s) + { + int index = info->FLOATL_MANT_BITS - (s - bin) - 1; + if (index < 0) break; + if (index >= 0 && *s == '1') + { + int part = index / 32; + int bit = index % 32; + + info->buffer[part] |= (1 << bit); + } + s++; + } + + return info; +} + +FLINFO *floatl_cfg_int_zero(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + return info; +} + +FLINFO *floatl_cfg_const_0(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + return info; +} + +FLINFO *floatl_cfg_const_1(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + info->buffer[info->FLOATL_U32_PARTS - 1] &= 0xBFFFFFFF; + + return info; +} + +FLINFO *floatl_cfg_const_1eX(FLINFO *info, uint32_t e) +{ + if (e >= sizeof(fle_list) / sizeof(fle_list[0])) return NULL; + + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp(info, fle_list[e].exp); + floatl_cfg_set_mant(info, fle_list[e].mantBin); + + return info; +} + +FLINFO *floatl_cfg_inf(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + + return info; +} + +FLINFO *floatl_cfg_nan(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + info->buffer[info->FLOATL_U32_PARTS - 1] |= 0x80000000; + + return info; +} + +FLINFO *floatl_cfg_all_sign(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + info->buffer[info->FLOATL_U32_PARTS - 1] |= 0x80000000; + + return info; +} + +FLINFO *floatl_cfg_all_exp(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + + return info; +} + +FLINFO *floatl_cfg_all_mant(FLINFO *info) +{ + memset(info->buffer, -1, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0); + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~0x80000000); + + return info; +} + +FLINFO *floatl_cfg_all_exp_mant(FLINFO *info) +{ + memset(info->buffer, -1, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~0x80000000); + + return info; +} + +FLINFO *floatl_cfg_hide_mant_bit(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 1); + + return info; +} + +FLINFO *floatl_cfg_mant_plus_max(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 8); + + return info; +} + +FLINFO *floatl_cfg_mant_whole(FLINFO *info) +{ + memset(info->buffer, -1, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 1); + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~0x80000000); + + return info; +} + +void floatl_cfg_generate(uint32_t bits, const char *filename) +{ + #define MINBITS 64 + #define NEWLINE "\n" // "\r\n" // + + FILE* output = stdout; // Default output to standard output + if (filename != NULL) + { + output = fopen(filename, "w"); + if (output == NULL) + { + fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE); + return; + } + } + + /* The number of bits in an floatl needs to be an exponent of two */ + if ((bits & (bits - 1)) != 0) + { + fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE); + return; + } + + /* Limiting the minimum bit */ + if (bits < MINBITS) + { + fprintf(stdout, "[ERROR] `bits` too small\r\b"); + return; + } + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config start */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == MINBITS) + { + fprintf(output, "#define FLOATL_USE_%uBITS"NEWLINE, tb); + } + else + { + fprintf(output, "// #define FLOATL_USE_%uBITS"NEWLINE, tb); + } + } + fprintf(output, NEWLINE); + + floatl temp; + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == MINBITS) + { + fprintf(output, "#if defined(FLOATL_USE_%uBITS)"NEWLINE, tb); + } + else + { + fprintf(output, "#elif defined(FLOATL_USE_%uBITS)"NEWLINE, tb); + } + + FLINFO info; + info.FLOATL_BIT_PARTS = tb; + info.FLOATL_U32_PARTS = info.FLOATL_BIT_PARTS >> (5); + info.FLOATL_U16_PARTS = info.FLOATL_BIT_PARTS >> (4); + info.FLOATL_EXP_BITS = floatl_cfg_gen_exp(info.FLOATL_BIT_PARTS); + info.FLOATL_MANT_BITS = info.FLOATL_BIT_PARTS - info.FLOATL_EXP_BITS - 1; + info.FLOATL_MANT_PARTS = info.FLOATL_MANT_BITS >> 5; + info.FLOATL_MANT_HIGH_BITS = info.FLOATL_MANT_BITS & 0x1F; + info.FLOATL_EXP_MID_VALUE = (uint32_t)pow(2, info.FLOATL_EXP_BITS - 1) - 1; + info.FLOATL_EXP_WHL_VALUE = (uint32_t)pow(2, info.FLOATL_EXP_BITS) - 1; + info.FLOATL2_BIT_PARTS = info.FLOATL_BIT_PARTS * 2; + info.FLOATL2_U32_PARTS = info.FLOATL2_BIT_PARTS >> (5); + info.FLOATL2_U16_PARTS = info.FLOATL2_BIT_PARTS >> (4); + + fprintf(output, "#define __FLOATL_BIT_PARTS__ %u"NEWLINE, info.FLOATL_BIT_PARTS ); + fprintf(output, "#define __FLOATL_U32_PARTS__ %u"NEWLINE, info.FLOATL_U32_PARTS ); + fprintf(output, "#define __FLOATL_U16_PARTS__ %u"NEWLINE, info.FLOATL_U16_PARTS ); + fprintf(output, "#define __FLOATL_EXP_BITS__ %u"NEWLINE, info.FLOATL_EXP_BITS ); + fprintf(output, "#define __FLOATL_MANT_BITS__ %u"NEWLINE, info.FLOATL_MANT_BITS ); + fprintf(output, "#define __FLOATL_MANT_PARTS__ %u"NEWLINE, info.FLOATL_MANT_PARTS ); + fprintf(output, "#define __FLOATL_MANT_HIGH_BITS__ %u"NEWLINE, info.FLOATL_MANT_HIGH_BITS ); + fprintf(output, "#define __FLOATL_EXP_MID_VALUE__ %u"NEWLINE, info.FLOATL_EXP_MID_VALUE ); + fprintf(output, "#define __FLOATL_EXP_WHL_VALUE__ %u"NEWLINE, info.FLOATL_EXP_WHL_VALUE ); + + fprintf(output, "#define __FLOATL2_BIT_PARTS__ %u"NEWLINE, info.FLOATL2_BIT_PARTS ); + fprintf(output, "#define __FLOATL2_U32_PARTS__ %u"NEWLINE, info.FLOATL2_U32_PARTS ); + fprintf(output, "#define __FLOATL2_U16_PARTS__ %u"NEWLINE, info.FLOATL2_U16_PARTS ); + + fprintf(output, "#define __FLOATL_CONST_0__ "); floatl_cfg_const_out(output, floatl_cfg_const_0(&info) ); + fprintf(output, "#define __FLOATL_CONST_1__ "); floatl_cfg_const_out(output, floatl_cfg_const_1(&info) ); + fprintf(output, "#define __FLOATL_CONST_1e0__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,0) ); + fprintf(output, "#define __FLOATL_CONST_1e1__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,1) ); + fprintf(output, "#define __FLOATL_CONST_1e2__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,2) ); + fprintf(output, "#define __FLOATL_CONST_1e3__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,3) ); + fprintf(output, "#define __FLOATL_CONST_1e4__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,4) ); + fprintf(output, "#define __FLOATL_CONST_1e5__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,5) ); + fprintf(output, "#define __FLOATL_CONST_1e6__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,6) ); + fprintf(output, "#define __FLOATL_CONST_1e7__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,7) ); + fprintf(output, "#define __FLOATL_CONST_1e8__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,8) ); + fprintf(output, "#define __FLOATL_CONST_1e9__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,9) ); + fprintf(output, "#define __FLOATL_CONST_1e10__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,10) ); + fprintf(output, "#define __FLOATL_CONST_1e11__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,11) ); + fprintf(output, "#define __FLOATL_CONST_1e12__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,12) ); + fprintf(output, "#define __FLOATL_CONST_1e13__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,13) ); + fprintf(output, "#define __FLOATL_CONST_1e14__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,14) ); + fprintf(output, "#define __FLOATL_CONST_1e15__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,15) ); + fprintf(output, "#define __FLOATL_INT_ZERO__ "); floatl_cfg_const_out(output, floatl_cfg_int_zero(&info) ); + fprintf(output, "#define __FLOATL_INF__ "); floatl_cfg_const_out(output, floatl_cfg_inf(&info) ); + fprintf(output, "#define __FLOATL_NAN__ "); floatl_cfg_const_out(output, floatl_cfg_nan(&info) ); + fprintf(output, "#define __FLOATL_ALL_SIGN__ "); floatl_cfg_const_out(output, floatl_cfg_all_sign(&info) ); + fprintf(output, "#define __FLOATL_ALL_EXP__ "); floatl_cfg_const_out(output, floatl_cfg_all_exp(&info) ); + fprintf(output, "#define __FLOATL_ALL_MANT__ "); floatl_cfg_const_out(output, floatl_cfg_all_mant(&info) ); + fprintf(output, "#define __FLOATL_ALL_EXP_MANT__ "); floatl_cfg_const_out(output, floatl_cfg_all_exp_mant(&info) ); + fprintf(output, "#define __FLOATL_HIDE_MANT_BIT__ "); floatl_cfg_const_out(output, floatl_cfg_hide_mant_bit(&info) ); + fprintf(output, "#define __FLOATL_MANT_PLUS_MAX__ "); floatl_cfg_const_out(output, floatl_cfg_mant_plus_max(&info) ); + fprintf(output, "#define __FLOATL_MANT_WHL__ "); floatl_cfg_const_out(output, floatl_cfg_mant_whole(&info) ); + } + + fprintf(output, "#endif"NEWLINE); + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config end */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + 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 `FLOATL_MAX_DEC`\r\n"); + } + else + { + printf("[INFO] The configuration has been generated, copy it to the `floatl_cfg.h` range specified\r\n"); + } + + return 0; +} + +/*----------------------------------------------------------------------------------*/ +/* Generate configuration [END] */ +/*----------------------------------------------------------------------------------*/ +#endif + +#endif + diff --git a/source/01_general/intl.c b/source/07_math/intl.c similarity index 60% rename from source/01_general/intl.c rename to source/07_math/intl.c index 6eff846..45e9c5c 100644 --- a/source/01_general/intl.c +++ b/source/07_math/intl.c @@ -6,7 +6,7 @@ * \unit intl * \brief This is a simple large inter number calculate module for C language * \author Lamdonn - * \version v1.0.0 + * \version v1.1.0 * \license GPL-2.0 * \copyright Copyright (C) 2023 Lamdonn. ********************************************************************************************************/ @@ -22,15 +22,15 @@ 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, + * This function computes the sum of two 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). + * \return The sum of a and b as an intl. */ intl intl_add(intl a, intl b) { @@ -38,7 +38,7 @@ intl intl_add(intl a, intl b) uint16_t carry = 0; /** Carry bit */ // Perform addition for each 16-bit part - for (int i = 0; i < INTL_U16_PARTS; i++) + 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; @@ -52,22 +52,22 @@ intl intl_add(intl a, intl b) /** * \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 + * This function computes the difference of two 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). + * \return The result of a - b as an intl. */ 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++) + for (int i = 0; i < __INTL_U16_PARTS__; i++) { uint32_t diff = (uint32_t)a.u16[i] - (uint32_t)b.u16[i]; @@ -75,7 +75,7 @@ intl intl_sub(intl a, intl b) if (diff & 0xFFFF0000) /** Borrow occurred */ { // Adjust the higher parts to account for the borrow - for (int j = i + 1; j < INTL_U16_PARTS; j++) + 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 @@ -92,18 +92,18 @@ intl intl_sub(intl a, intl b) /** * \brief Increments the intl number by one. * - * This function increments a 128-bit integer (intl) by one. + * This function increments a 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). + * \return The incremented intl number as an intl. */ intl intl_inc(intl a) { // Increment each 32-bit part of the intl number - for (int i = 0; i < INTL_U32_PARTS; i++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { a.u32[i]++; // Increment the current part // Check if the current part overflowed @@ -118,19 +118,19 @@ intl intl_inc(intl a) /** * \brief Decrements the intl number by one. * - * This function decrements a 128-bit integer (intl) by one. + * This function decrements a 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). + * \return The decremented intl number as an intl. */ intl intl_dec(intl a) { // Decrement each 32-bit part of the intl number - for (int i = 0; i < INTL_U32_PARTS; i++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { // Check if the current part can be decremented if (a.u32[i] != 0) @@ -147,8 +147,8 @@ intl intl_dec(intl a) /** * \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 + * This function performs multiplication of two 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 @@ -156,21 +156,21 @@ intl intl_dec(intl a) * * \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). + * \return The product of a and b as an intl. */ 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 + intl result = __INTL_ZERO__; /** 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++) + 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++) + for (int j = 0; j < __INTL_U16_PARTS__; j++) { - if (i + j < INTL_U16_PARTS) + 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; @@ -182,10 +182,10 @@ static intl intl_umul(intl a, intl b) carry = 0; // Reset carry for the addition phase // Combine results from the temporary storage - for (int i = 0; i < INTL_U16_PARTS; i++) + 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++) + for (int j = 0; j < __INTL_U16_PARTS__; j++) { add += temp[j].u16[i]; // Accumulate results from temp } @@ -200,7 +200,7 @@ static intl intl_umul(intl a, intl b) /** * \brief Multiplies two intl numbers. * - * This function multiplies two 128-bit integers (intl) and returns + * This function multiplies two 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. @@ -209,22 +209,22 @@ static intl intl_umul(intl a, intl b) * * \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). + * \return The product of a and b as an intl. */ intl intl_mul(intl a, intl b) { - intl result = {0}; // Initialize the result to 0 + intl result = __INTL_ZERO__; // 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) + 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) + if (b.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result b = intl_neg(b); // Negate the second operand @@ -243,7 +243,7 @@ intl intl_mul(intl a, intl b) /** * \brief Divides one intl unsigned number by another. * - * This function performs division of one 128-bit unsigned integer (intl) + * This function performs division of one 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 @@ -251,22 +251,18 @@ intl intl_mul(intl a, intl b) * * \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). + * \return The quotient of a divided by b as an intl. */ 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 */ - } + if (intl_sign(b) == 0) { INTL_E(INTL_E_DIV_0, '0'); return __INTL_ZERO__; } - intl result = {0}; // Initialize the result to zero - intl remainder = {0}; // Initialize the remainder to zero + intl result = __INTL_ZERO__; // Initialize the result to zero + intl remainder = __INTL_ZERO__; // Initialize the remainder to zero /** Calculate bit by bit from the highest bit */ - for (int i = INTL_BIT_PARTS - 1; i >= 0; i--) + 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 @@ -288,7 +284,7 @@ static intl intl_udiv(intl a, intl b, intl *mod) /** * \brief Divides one intl number by another. * - * This function performs division of two 128-bit integers (intl) + * This function performs division of two 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 @@ -298,22 +294,22 @@ static intl intl_udiv(intl a, intl b, intl *mod) * * \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). + * \return The quotient of a divided by b as an intl. */ intl intl_div(intl a, intl b) { - intl result = {0}; // Initialize the result to 0 + intl result = __INTL_ZERO__; // 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) + 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) + if (b.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result b = intl_neg(b); // Negate the divisor @@ -333,18 +329,18 @@ intl intl_div(intl a, intl b) * \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 + * 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). + * \return The remainder of a divided by b as an intl. */ static intl intl_umod(intl a, intl b) { - intl mod = {0}; + intl mod = __INTL_ZERO__; intl_udiv(a, b, &mod); return mod; } @@ -353,7 +349,7 @@ static intl intl_umod(intl a, intl b) * \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 + * 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 @@ -363,15 +359,15 @@ static intl intl_umod(intl a, intl b) * * \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). + * \return The remainder of a divided by b as an intl. */ intl intl_mod(intl a, intl b) { - intl result = {0}; // Initialize result to zero + intl result = __INTL_ZERO__; // 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) + if (a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result a = intl_neg(a); // Negate the dividend @@ -390,24 +386,24 @@ intl intl_mod(intl a, intl b) /** * \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 + * This function performs a left bitwise shift on a intl. + * The shift b 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. + * \param[in] b: The number of bits to shift to the left. * \return The left-shifted intl number. */ -intl intl_shl(intl a, uint32_t amount) +intl intl_shl(intl a, uint32_t b) { - 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 + intl result = __INTL_ZERO__; // Initialize the result to zero + int u32bias = b / 32; // Number of whole 32-bit parts to shift + int bitsbias = b % 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++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { if (i < u32bias) { @@ -427,28 +423,28 @@ intl intl_shl(intl a, uint32_t amount) /** * \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 + * This function performs a right bitwise shift on a intl. + * The shift b 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. + * \param[in] b: The number of bits to shift to the right. * \return The right-shifted intl number. */ -intl intl_shr(intl a, uint32_t amount) +intl intl_shr(intl a, uint32_t b) { - 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 + intl result = __INTL_ZERO__; // Initialize the result to zero + int u32bias = b / 32; // Number of whole 32-bit parts to shift + int bitsbias = b % 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++) + 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) + if (i > __INTL_U32_PARTS__ - u32bias - 1 && __INTL_U32_PARTS__ - u32bias - 1 >= 0) { result.u32[i] = 0; // Set shifted-out parts to zero } @@ -456,9 +452,9 @@ intl intl_shr(intl a, uint32_t amount) { // 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) ? + (((i + u32bias + 1) < __INTL_U32_PARTS__ && bitsbias > 0) ? (a.u32[i + u32bias + 1] << (32 - bitsbias)) : - ((a.u32[INTL_U32_PARTS - 1] & 0x80000000) ? 0xFFFFFFFF : 0)); + ((a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) ? 0xFFFFFFFF : 0)); } } @@ -468,21 +464,21 @@ intl intl_shr(intl a, uint32_t amount) /** * \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 + * This function computes the bitwise AND of two 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). + * \return The result of a AND b as an intl. */ 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++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { result.u32[i] = a.u32[i] & b.u32[i]; // Compute AND for each part } @@ -492,21 +488,21 @@ intl intl_and(intl a, intl b) /** * \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 + * This function computes the bitwise OR of two 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). + * \return The result of a OR b as an intl. */ 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++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { result.u32[i] = a.u32[i] | b.u32[i]; // Compute OR for each part } @@ -516,21 +512,21 @@ intl intl_or(intl a, intl b) /** * \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 + * This function computes the bitwise XOR of two 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). + * \return The result of a XOR b as an intl. */ 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++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { result.u32[i] = a.u32[i] ^ b.u32[i]; // Compute XOR for each part } @@ -540,19 +536,19 @@ intl intl_xor(intl a, intl b) /** * \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 + * This function computes the bitwise NOT (negation) of a 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). + * \return The bitwise negation of a as an intl. */ 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++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { result.u32[i] = ~a.u32[i]; // Compute NOT for each part } @@ -562,7 +558,7 @@ intl intl_not(intl a) /** * \brief Computes the absolute value of an intl number. * - * This function checks if the given 128-bit unsigned integer (intl) + * This function checks if the given 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 @@ -575,7 +571,7 @@ intl intl_not(intl 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) + 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 } @@ -585,7 +581,7 @@ intl intl_abs(intl a) * * 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 + * into a intl. It handles optional signs * and base prefixes, and processes the string from the end to * the start for efficiency in base conversions. * @@ -598,7 +594,7 @@ 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 result = __INTL_ZERO__; // 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 @@ -607,11 +603,11 @@ intl intl_from(const char *str) switch (*p) { case '0': { - if (p[1] == 0) { return (intl){0}; } // Handle case of "0" + if (p[1] == 0) { return __INTL_ZERO__; } // 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}; + else if (p[1] < '0' || p[1] > '9') { INTL_E(INTL_E_INVALID_CAHRACTER, p[1]); return __INTL_ZERO__; } p += 2; // Move past the prefix } break; case '-': { sign = -1; } // Handle negative sign @@ -629,58 +625,53 @@ intl intl_from(const char *str) 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 + /** Check if the character is a digit */ + if (c < '0' || c > '9') { INTL_E(INTL_E_INVALID_CAHRACTER, *s); return __INTL_ZERO__; } + + 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}); - /** 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); - } + // Apply sign if negative + if (sign == -1) 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) + 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])) + if (c >= '0' && c <= '9') c -= '0'; + else if (c >= 'A' && c <= 'F') c -= 55; // c = c - 'A' + 10 // 55 + else if (c >= 'a' && c <= 'f') c -= 87; // c = c - 'a' + 10 // 87 + else { INTL_E(INTL_E_INVALID_CAHRACTER, *s); return __INTL_ZERO__; } + + if (c >= ttable[type]) { INTL_E(INTL_E_INVALID_CAHRACTER, *s); return __INTL_ZERO__; } + + result.u32[index] |= (c << bit); // Set the value in the corresponding bit + if ((type == 2) && (bit > 29) && (index < __INTL_U32_PARTS__ - 1)) // For oct, stitching to high u32 is required, 2,1,0,31,30,29 { - 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 - } + result.u32[index + 1] |= (c >> (32 - bit)); } - else + bit += btable[type]; // Update the bit position + if (bit >= 32) // If bit exceeds 32, move to the next part { - printf("Invalid character in input string: %c\n", *s); // Error handling - return (intl){0}; // Return zero for invalid input + bit -= 32; // Reset bit position + index++; // Move to the next u32 part } + s--; // Move to the previous character } } @@ -694,14 +685,14 @@ intl intl_from(const char *str) * 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. + * to the custom muti-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}; + intl result = __INTL_ZERO__; memcpy(&result, &value, sizeof(value)); if (value < 0) { @@ -713,8 +704,8 @@ intl intl_from2(int value) /** * \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 + * This function checks the sign of the given 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. @@ -727,10 +718,10 @@ intl intl_from2(int value) 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; + 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--) + 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 } @@ -738,169 +729,179 @@ int intl_sign(intl a) return 0; // Return 0 if all parts are zero } +#define FLAGS_ZEROPAD (0x01) +#define FLAGS_LEFT (0x02) +#define FLAGS_PLUS (0x04) +#define FLAGS_SPACE (0x08) +#define FLAGS_HASH (0x10) +#define PRINT_CHAR(c) do { if (length < max) { buffer[length++] = (c); } else return -2; } while (0) + /** - * \brief Converts an intl number to a decimal string. + * \brief Converts an intl number to a 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. + * This function converts a given intl into a string representation. + * Including dec, bin, oct, hex string. * * \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. + * \param[out] buffer: The buffer to store the resulting string. + * It should be large enough to hold the representation. + * \param[in] size: The size of buffer, can refer to `INTL_PRINT_MAX`. + * \param[in] format: Printf-like format, [flags][width][type]. + * flags: '0' '-' '+' ' ' '#' + * width: dec numeber + * type: 'x' 'X' 'o' 'O' 'b' 'B' 'd' 'i' 'u' + * \return The length of the string that was converted successfully. + * 0: Invalid convertion + * -1: Null pointer `buffer` + * -2: `size` is too small + * -3: Null pointer `format` */ -const char* intl_sdec(intl a, char buffer[INTL_MAX_DEC]) +int intl_print(intl a, char *buffer, uint32_t size, const char *format) { - 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 + 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 + int length = 0; + int i = 0, j = 0; + uint32_t flags = 0, width = 0; + uint32_t max = size - 1; + char c = 0; + char prefix[2] = {0, 0}; + char prelen = 0; - // 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 - } + if (!buffer) return -1; + if (size < 2) return -2; + if (!format) return -3; - /** Calculate decimal string of intl */ - while (intl_ucmp(temp, (intl){0}) > 0) // While the number is positive + for (; *format; format++) { - 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 - } + if (length > 0) break; - // 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) + while (1) { - *p++ = '-'; // Append negative sign + if (*format == '0') { flags |= FLAGS_ZEROPAD; format++; } + else if (*format == '-') { flags |= FLAGS_LEFT; format++; } + else if (*format == '+') { flags |= FLAGS_PLUS; format++; } + else if (*format == ' ') { flags |= FLAGS_SPACE; format++; } + else if (*format == '#') { flags |= FLAGS_HASH; format++; } + else break; } - *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 + /* Convert width */ + while ((*format >= '0') && (*format <= '9')) width = width * 10U + (unsigned int)(*format++ - '0'); + if (width > max) return -1; + + /* format distribution */ + switch (*format) { - char t = *s; // Temporary variable for swapping - *s = *p; // Swap start and end - *p = t; - s++; // Move pointers towards the center - p--; + case 'X': + case 'x': type++; + case 'O': + case 'o': type++; + case 'B': + case 'b': type++; + { + int valid = 0; + int u32part = 0; + int u32bias = 0; + + if (flags & FLAGS_HASH) + { + prefix[prelen++] = '0'; + prefix[prelen++] = *format; + } + + if (intl_eq(a, __INTL_ZERO__)) PRINT_CHAR('0'); + else + { + for (valid = __INTL_U32_PARTS__ - 1; valid >= 0; valid--) + { + if (a.u32[valid] != 0) break; + } + + while (u32part <= valid) + { + c = (a.u32[u32part] >> u32bias) & ((1 << btable[type]) - 1); + + /* For hexadecimal, convert the letters */ + if (c >= 10) c += (*format == 'x' ? 39 : 7); + + /* The bits of the previous part need to be concatenated to form octal */ + if (type == 2 && u32part < valid && u32bias > 29) c |= ((a.u32[u32part + 1] << (32 - u32bias)) & 0x7); + + PRINT_CHAR(c + '0'); + + /* Update the u32 index of the current transition and the bit bias */ + u32bias += btable[type]; + if (u32bias >= 32) + { + u32part++; + u32bias %= 32; + } + + /* If there are no valid bits left, the conversion is exited */ + if ((u32part == valid) && ((a.u32[u32part] >> u32bias) == 0)) break; + } + } + } break; + case 'u': + case 'd': + case 'i': + { + intl ten = intl(10); /** Base 10 for conversion */ + intl remainder; // To hold the remainder during division + intl temp = a; // Temporary variable for manipulation + + if (intl_eq(a, __INTL_ZERO__)) PRINT_CHAR('0'); + else + { + // Check if the number is negative + if (*format != 'u' && a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) temp = intl_neg(a); // Negate the number for conversion + + /** Calculate decimal string of intl */ + while (intl_ucmp(temp, __INTL_ZERO__) > 0) // While the number is positive + { + temp = intl_udiv(temp, ten, &remainder); // Get remainder when divided by 10, and update temp + PRINT_CHAR('0' + remainder.u32[0]); // Convert remainder to character, store character in buffer + } + + // If the original number was negative, add '-' sign + if (*format != 'u' && a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) prefix[prelen++] = '-'; // Append negative sign + else + { + if (flags & FLAGS_PLUS) prefix[prelen++] = '+'; + } + } + } break; + default: + return 0; } } - 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 */ + /* Right align */ + if (!((flags & FLAGS_LEFT)) && (flags & FLAGS_ZEROPAD)) while (length + prelen < width) PRINT_CHAR('0'); + while (prelen > 0) PRINT_CHAR(prefix[--prelen]); + if (!((flags & FLAGS_LEFT)) && !(flags & FLAGS_ZEROPAD)) while (length < width) PRINT_CHAR(' '); - // 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--) + /* Reverse */ + for (i = 0, j = length - 1; i < j; i++, j--) { - 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; + c = buffer[i]; // Temporary variable for swapping + buffer[i] = buffer[j]; // Swap start and end + buffer[j] = c; } - /** Prevent leading zero */ - while (*buffer == '0') buffer++; // Uncomment this line to remove leading zeros + /* Left align */ + if (flags & FLAGS_LEFT) while (length < width) PRINT_CHAR(' '); - /** a == 0, print 0 only */ - if (p == buffer) - { - buffer[0] = '0'; - buffer[1] = '\0'; - } + buffer[length] = 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 + return length; } /** * \brief Compares two intl unsigned numbers. * - * This function compares two 128-bit unsigned integers (intl) + * This function compares two 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 @@ -914,7 +915,7 @@ const char* intl_sbin(intl a, char buffer[INTL_MAX_BIN]) 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--) + 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 @@ -925,7 +926,7 @@ static int intl_ucmp(intl a, intl b) /** * \brief Compares two intl numbers. * - * This function compares two 128-bit integers (intl) and + * This function compares two 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). @@ -935,10 +936,10 @@ static int intl_ucmp(intl a, intl b) * * \return 1 if a > b, -1 if a < b, 0 if a == b. */ -int intl_cmp(intl a, intl b) +static 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--) + 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 @@ -947,11 +948,89 @@ int intl_cmp(intl a, intl b) return 0; // a is equal to b } +/** + * \brief Compares two intl numbers, determine whether a < b. + * + * \param[in] a: The first number to compare. + * \param[in] b: The second number to compare. + * + * \return a < b ? + */ +int intl_lt(intl a, intl b) +{ + return intl_cmp(a, b) < 0 ? 1 : 0; +} + +/** + * \brief Compares two intl numbers, determine whether a <= b. + * + * \param[in] a: The first number to compare. + * \param[in] b: The second number to compare. + * + * \return a <= b ? + */ +int intl_le(intl a, intl b) +{ + return intl_cmp(a, b) <= 0 ? 1 : 0; +} + +/** + * \brief Compares two intl numbers, determine whether a == b. + * + * \param[in] a: The first number to compare. + * \param[in] b: The second number to compare. + * + * \return a == b ? + */ +int intl_eq(intl a, intl b) +{ + return intl_cmp(a, b) == 0 ? 1 : 0; +} + +/** + * \brief Compares two intl numbers, determine whether a != b. + * + * \param[in] a: The first number to compare. + * \param[in] b: The second number to compare. + * + * \return a != b ? + */ +int intl_ne(intl a, intl b) +{ + return intl_cmp(a, b) != 0 ? 1 : 0; +} + +/** + * \brief Compares two intl numbers, determine whether a > b. + * + * \param[in] a: The first number to compare. + * \param[in] b: The second number to compare. + * + * \return a > b ? + */ +int intl_gt(intl a, intl b) +{ + return intl_cmp(a, b) > 0 ? 1 : 0; +} + +/** + * \brief Compares two intl numbers, determine whether a >= b. + * + * \param[in] a: The first number to compare. + * \param[in] b: The second number to compare. + * + * \return a >= b ? + */ +int intl_ge(intl a, intl b) +{ + return intl_cmp(a, b) >= 0 ? 1 : 0; +} + /** * \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 + * This function calculates the negative representation of a given 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. @@ -961,10 +1040,10 @@ int intl_cmp(intl a, intl b) */ intl intl_neg(intl a) { - intl result = {0}; + intl result = __INTL_ZERO__; // First, bitwise NOT (invert) the input number - for (int i = 0; i < INTL_U32_PARTS; i++) + for (int i = 0; i < __INTL_U32_PARTS__; i++) { result.u32[i] = ~a.u32[i]; } diff --git a/source/07_math/intl.h b/source/07_math/intl.h new file mode 100644 index 0000000..16c42ce --- /dev/null +++ b/source/07_math/intl.h @@ -0,0 +1,113 @@ + +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file intl.h + * \unit intl + * \brief This is a simple large inter number calculate module for C language + * \author Lamdonn + * \version v1.1.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __intl_H +#define __intl_H + +#include +#include +#include +#include +#include +#include "intl_cfg.h" + +/* Version infomation */ + +#define INTL_V_MAJOR 1 +#define INTL_V_MINOR 1 +#define INTL_V_PATCH 0 + +/* Universal constant */ + +#define INTL_MAX __INTL_MAX__ +#define INTL_MIN __INTL_MIN__ +#define INTL_ZERO __INTL_ZERO__ + +/* Print the max buffer size, no width is specified in `intl_print` format */ +#define INTL_PRINT_MAX __INTL_P_MAX_BIN__ + +/* Error type */ + +#define INTL_E_DIV_0 0 // Division by zero +#define INTL_E_INVALID_CAHRACTER 1 // Invalid character in input string + +/** + * \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 b); +intl intl_shr(intl a, uint32_t b); +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); +int intl_print(intl a, char *buffer, uint32_t size, const char *format); +int intl_lt(intl a, intl b); +int intl_le(intl a, intl b); +int intl_eq(intl a, intl b); +int intl_ne(intl a, intl b); +int intl_gt(intl a, intl b); +int intl_ge(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) + +/** + * \brief Converts an intl number to string. + * \param[in] a: The intl number to convert. + * \param[out] buffer: The buffer to store the resulting string. + * It should be large enough to hold the representation. + * \param[in] size: The size of buffer, can refer to `INTL_PRINT_MAX`. + * \param[in] format: Printf-like format, [flags][width][type]. + * flags: '0' '-' '+' ' ' '#' + * width: dec numeber +* type: 'x' 'X' 'o' 'O' 'b' 'B' 'd' 'i' 'u' + * \return String converted or "invalid" fail. + */ +#define intl_show(a, b, s, f) (intl_print((a), (b), (s), (f)) > 0 ? (b) : "invalid") + +#endif + diff --git a/source/07_math/intl_cfg.h b/source/07_math/intl_cfg.h new file mode 100644 index 0000000..38c8af2 --- /dev/null +++ b/source/07_math/intl_cfg.h @@ -0,0 +1,263 @@ + +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * 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.1.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __intl_cfg_H +#define __intl_cfg_H + +/* Error handling configuration */ +#define INTL_E(e, c) do { printf("[ERROR] Code %d,%c\r\n", (e), (c)); } while (0) +// #define INTL_E(e, c) + +/* + * 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_64BITS +// #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_64BITS) +#define __INTL_BIT_PARTS__ 64 +#define __INTL_U32_PARTS__ 2 +#define __INTL_U16_PARTS__ 4 +#define __INTL_P_MAX_BIN__ 67 +#define __INTL_P_MAX_DEC__ 20 +#define __INTL_P_MAX_HEX__ 19 +#define __INTL_MAX__ (intl){.u32={-1,0x7FFFFFFF,}} +#define __INTL_MIN__ (intl){.u32={0,0x80000000,}} +#define __INTL_ZERO__ (intl){.u32={0,0,}} +#elif defined(INTL_USE_128BITS) +#define __INTL_BIT_PARTS__ 128 +#define __INTL_U32_PARTS__ 4 +#define __INTL_U16_PARTS__ 8 +#define __INTL_P_MAX_BIN__ 131 +#define __INTL_P_MAX_DEC__ 40 +#define __INTL_P_MAX_HEX__ 35 +#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_P_MAX_BIN__ 259 +#define __INTL_P_MAX_DEC__ 78 +#define __INTL_P_MAX_HEX__ 67 +#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_P_MAX_BIN__ 515 +#define __INTL_P_MAX_DEC__ 155 +#define __INTL_P_MAX_HEX__ 131 +#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_P_MAX_BIN__ 1027 +#define __INTL_P_MAX_DEC__ 309 +#define __INTL_P_MAX_HEX__ 259 +#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_P_MAX_BIN__ 2051 +#define __INTL_P_MAX_DEC__ 618 +#define __INTL_P_MAX_HEX__ 515 +#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_P_MAX_BIN__ 4099 +#define __INTL_P_MAX_DEC__ 1234 +#define __INTL_P_MAX_HEX__ 1027 +#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_P_MAX_BIN__ 8195 +#define __INTL_P_MAX_DEC__ 2468 +#define __INTL_P_MAX_HEX__ 2051 +#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 /* Config function */ +void intl_gen_cfg(uint32_t bits, const char *filename) +{ + #define MINBITS 64 + #define NEWLINE "\n" // "\r\n" // + + FILE* output = stdout; // Default output to standard output + if (filename != NULL) + { + output = fopen(filename, "w"); + if (output == NULL) + { + fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE); + return; + } + } + + /* The number of bits in an intl needs to be an exponent of two */ + if ((bits & (bits - 1)) != 0) + { + fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE); + return; + } + + /* Limiting the minimum bit */ + if (bits < MINBITS) + { + fprintf(stdout, "[ERROR] `bits` too small\r\b"); + return; + } + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config start */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == bits) + { + fprintf(output, "#define INTL_USE_%uBITS"NEWLINE, tb); + } + else + { + fprintf(output, "// #define INTL_USE_%uBITS"NEWLINE, tb); + } + } + fprintf(output, ""NEWLINE); + + intl temp; + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == MINBITS) + { + fprintf(output, "#if defined(INTL_USE_%uBITS)"NEWLINE, tb); + } + else + { + fprintf(output, "#elif defined(INTL_USE_%uBITS)"NEWLINE, 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 + 3; // "0b" + '\0' + MAX_DEC = MAX_BIN; // First apply as MAX bin maximum value, and then according to the actual calculation + MAX_HEX = (BIT_PARTS >> (2)) + 3; // "0x" + '\0' + + /* The current configuration is applied */ + if (sizeof(temp) == (bits >> 3)) + { + char buffer[__INTL_P_MAX_BIN__]; + MAX_DEC = intl_print(intl_shl(intl(1), BIT_PARTS - 1), buffer, sizeof(buffer), "d") + 1; // '\0' + } + + fprintf(output, "#define __INTL_BIT_PARTS__ %u"NEWLINE, BIT_PARTS); + fprintf(output, "#define __INTL_U32_PARTS__ %u"NEWLINE, U32_PARTS); + fprintf(output, "#define __INTL_U16_PARTS__ %u"NEWLINE, U16_PARTS); + fprintf(output, "#define __INTL_P_MAX_BIN__ %u"NEWLINE, MAX_BIN); + fprintf(output, "#define __INTL_P_MAX_DEC__ %u"NEWLINE, MAX_DEC); + fprintf(output, "#define __INTL_P_MAX_HEX__ %u"NEWLINE, MAX_HEX); + + /* __INTL_MAX__ */ + fprintf(output, "#define __INTL_MAX__ (intl){.u32={"); + for (uint32_t i = 0; i < U32_PARTS; i++) + { + fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x7FFFFFFF" : "-1"); + } + fprintf(output, "}}"NEWLINE); + + /* __INTL_MIN__ */ + fprintf(output, "#define __INTL_MIN__ (intl){.u32={"); + for (uint32_t i = 0; i < U32_PARTS; i++) + { + fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x80000000" : "0"); + } + fprintf(output, "}}"NEWLINE); + + /* __INTL_ZERO__ */ + fprintf(output, "#define __INTL_ZERO__ (intl){.u32={"); + for (uint32_t i = 0; i < U32_PARTS; i++) + { + fprintf(output, "0,"); + } + fprintf(output, "}}"NEWLINE); + } + + fprintf(output, "#endif"NEWLINE); + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config end */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + fprintf(stdout, "\r\n\r\n-------------------------------------------------------------\r\n"NEWLINE); + + /* The current configuration is not applied */ + if (sizeof(temp) != (bits >> 3)) + { + fprintf(stdout, "[TODO][%s] Apply the current configuration and run it again to get the new `__INTL_P_MAX_DEC__`"NEWLINE, filename); + } + else + { + fprintf(stdout, "[INFO][%s] The configuration has been generated, copy it to the `intl_cfg.h` range specified"NEWLINE, filename); + } + + if (filename != NULL) + { + fclose(output); + } +} +#endif + +#endif + diff --git a/test/test.mk b/test/test.mk index 504a42a..975fea2 100644 --- a/test/test.mk +++ b/test/test.mk @@ -37,8 +37,9 @@ TEST_LIST += sList TEST_LIST += dList TEST_LIST += cQueue TEST_LIST += intl +TEST_LIST += floatl TEST_LIST += ramt TEST_LIST += romt -TEST_LIST += cpul +# TEST_LIST += cpul TEST_LIST += date TEST_LIST += unitt diff --git a/test/test_floatl.c b/test/test_floatl.c new file mode 100644 index 0000000..4c567b5 --- /dev/null +++ b/test/test_floatl.c @@ -0,0 +1,1470 @@ +#include +#include +#include +#include +#include +#include +#if defined(TEST_TARGET_floatl) +#include +#include +#include +#else +#include "init.h" +#include "command.h" +#include "unitt.h" +#include "kern.h" +#include "floatl.h" +#endif + +typedef union { + float float_; + uint32_t int_; + struct + { + uint32_t mantissa : 23; + uint32_t exponent : 8; + uint32_t sign : 1; + }; +} float_u; +typedef union +{ + double double_; + uint64_t int_; + struct + { + uint64_t mantissa : 52; + uint64_t exponent : 11; + uint64_t sign : 1; + } ; +#if defined(FLOATL_USE_64BITS) + floatl floatl_; +#endif +} double_u; + +static char buffer[1024] = {0}; + +static unsigned int b2o(unsigned int bits) +{ + unsigned int group = bits / 10; + unsigned int index = bits % 10; + unsigned int offset = 0; + unsigned int o = 0; + + if (index < 4) offset = 1; + else if (index < 7) offset = 2; + else offset = 3; + + return group * 3 + offset; +} + +// 去除字符串首尾的空白字符 +static void trim(char *str) +{ + int start = 0; + int end = strlen(str) - 1; + + // 去除字符串开头的空白字符 + while (isspace(str[start])) + { + start++; + } + + // 去除字符串末尾的空白字符 + while (end >= start && isspace(str[end])) + { + end--; + } + + // 移动字符到字符串开头 + int i; + for (i = 0; start <= end; i++, start++) + { + str[i] = str[start]; + } + str[i] = '\0'; +} + +// 字符串转换为 double 类型 +double double_from_string(const char *str) +{ + char temp[100]; + strcpy(temp, str); + trim(temp); + + int len = strlen(temp); + if (len == 0) + { + return 0.0; + } + + int sign = 1; + int i = 0; + + // 处理符号 + if (temp[0] == '-') + { + sign = -1; + i++; + } + else if (temp[0] == '+') + { + i++; + } + + // 检查是否为十六进制 + if (len >= i + 2 && temp[i] == '0' && (temp[i + 1] == 'x' || temp[i + 1] == 'X')) + { + i += 2; + double value = 0.0; + int point_found = 0; + double fraction = 1.0; + int exp_sign = 1; + int exp_value = 0; + + // 解析十六进制数字部分 + for (; i < len; i++) + { + if (temp[i] == '.') + { + point_found = 1; + continue; + } + else if (temp[i] == 'p' || temp[i] == 'P') + { + i++; + if (i < len && temp[i] == '-') + { + exp_sign = -1; + i++; + } + else if (i < len && temp[i] == '+') + { + i++; + } + // 解析十六进制指数部分 + for (; i < len; i++) + { + if (isdigit(temp[i])) + { + exp_value = exp_value * 10 + (temp[i] - '0'); + } + else + { + break; + } + } + break; + } + + if (isdigit(temp[i])) + { + value = value * 16 + (temp[i] - '0'); + } + else if (temp[i] >= 'a' && temp[i] <= 'f') + { + value = value * 16 + (temp[i] - 'a' + 10); + } + else if (temp[i] >= 'A' && temp[i] <= 'F') + { + value = value * 16 + (temp[i] - 'A' + 10); + } + + if (point_found) + { + fraction *= 16; + } + } + + value /= fraction; + value *= pow(2, exp_sign * exp_value); + return sign * value; + } + + // 处理十进制和指数计数法 + double value = 0.0; + int point_found = 0; + double fraction = 1.0; + int exp_sign = 1; + int exp_value = 0; + + for (; i < len; i++) + { + if (temp[i] == '.') + { + point_found = 1; + continue; + } + else if (temp[i] == 'e' || temp[i] == 'E') + { + i++; + if (i < len && temp[i] == '-') + { + exp_sign = -1; + i++; + } + else if (i < len && temp[i] == '+') + { + i++; + } + // 解析十进制指数部分 + for (; i < len; i++) + { + if (isdigit(temp[i])) + { + exp_value = exp_value * 10 + (temp[i] - '0'); + } + else + { + break; + } + } + break; + } + + if (isdigit(temp[i])) + { + value = value * 10 + (temp[i] - '0'); + } + + if (point_found) + { + fraction *= 10; + } + } + + value /= fraction; + value *= pow(10, exp_sign * exp_value); + return sign * value; +} + +static double double_from_uint64(uint64_t value) +{ + double_u v = {.int_ = value}; + return v.double_; +} + +static const char* float_show_raw(float x) +{ + float_u a = {.float_ = x}; + + printf("float --------------\r\n"); + printf("a.sign %u\r\n", a.sign); + printf("a.exponent %d\r\n", (int32_t)((int32_t)a.exponent - 127)); + + uint32_t mvalue = a.mantissa; + for (int i = 23 - 1; i >= 0; i--) + { + ((mvalue >> (i)) & 1) ? putchar('1') : putchar('0'); + } + printf("\r\n"); + + return 0; +} + +static const char* double_show_raw(double x) +{ + double_u a = {.double_ = x}; + + printf("[double]: sign(%u) exponent=%d\r\n", a.sign, (int32_t)((int32_t)a.exponent - 1023)); + + uint64_t mvalue = a.mantissa; + for (int i = 52 - 1; i >= 0; i--) + { + ((mvalue >> (i)) & 1) ? putchar('1') : putchar('0'); + } + printf("\r\n"); + + return 0; +} + +static const char* floatl_show_raw(floatl a, char *buffer, int size, const char *format) +{ + static char sbuffer[100] = {0}; + + char *base = sbuffer; + int index = 0; + int length = 100; + + printf("[floatl]: sign(%u) exponent=%d\r\n", a.sign, (int32_t)((int32_t)a.exponent - __FLOATL_EXP_MID_VALUE__)); + + uint32_t mvalue = a.mantissa; + for (int i = __FLOATL_MANT_HIGH_BITS__ - 1; i >= 0; i--) + { + ((mvalue >> (i)) & 1) ? putchar('1') : putchar('0'); + } + for (int m = __FLOATL_MANT_PARTS__ - 1; m >= 0; m--) + { + mvalue = a.mantissas[m]; + for (int i = 31; i >= 0; i--) + { + ((mvalue >> (i)) & 1) ? putchar('1') : putchar('0'); + } + } + printf("\r\n"); + + return base; +} + +static double double_random(void) +{ + uint64_t raw_bits = 0; + uint32_t sign = 0; + uint32_t exponent = 0; + uint64_t mantissa = 0; + double result; + + do { + // 定义一个 64 位无符号整数来模拟 double 的存储 + raw_bits = 0; + + // 随机生成符号位(0 或 1) + sign = rand() % 2; + raw_bits |= (uint64_t)sign << 63; + + // 随机生成指数位(范围 0 - 2047) + exponent = rand() % 2048; + raw_bits |= (uint64_t)exponent << 52; + + // 随机生成尾数位(范围 0 - 4503599627370495) + mantissa = (uint64_t)rand() << 32 | rand(); + raw_bits |= mantissa & 0xFFFFFFFFFFFFF; + + // 将 64 位无符号整数转换为 double 类型 + memcpy(&result, &raw_bits, sizeof(double)); + + } while (isnan(result) || isinf(result) || (exponent == 0 && mantissa != 0)); + + return result; +} + +static floatl floatl_random(void) +{ + floatl random = FLOATL_CONST_0; + +#if 0 + for (int i = 0; i < __FLOATL_U32_PARTS__; i++) + { + random.u32[i] = rand(); + } +#else + double r = double_random(); + memcpy(&random, &r, sizeof(double)); +#endif + return random; +} + +#define DOUBLE_RFLAG_NO_PLUS 0x01 +#define DOUBLE_RFLAG_NO_SUB 0x02 +#define DOUBLE_RFLAG_NO_ZERO 0x04 +#define DOUBLE_RFLAG_NO_WIDTH 0x08 +#define DOUBLE_RFLAG_NO_PRECISION 0x10 +#define DOUBLE_RFLAG_EXCLUDE_F 0x10 +#define DOUBLE_RFLAG_EXCLUDE_A 0x20 +#define DOUBLE_RFLAG_EXCLUDE_E 0x40 + +static void double_random_format(char *format, int size, int flags) +{ + const char baseArray[6] = {'F', 'f', 'A', 'a', 'E', 'e'}; + int flag_plus = rand() % 2; + int flag_sub = rand() % 2; + int flag_zero = rand() % 2; + int width = rand() % 50; + int precision = rand() % 10; + int base = 0; + + int len = 0; + char *f = format; + + *f++ = '%'; + if (flag_plus && !(flags & DOUBLE_RFLAG_NO_PLUS)) *f++ = '+'; + if (flag_sub && !(flags & DOUBLE_RFLAG_NO_SUB)) *f++ = '-'; + if (flag_zero && !(flags & DOUBLE_RFLAG_NO_ZERO)) *f++ = '0'; + if (!(flags & DOUBLE_RFLAG_NO_WIDTH)) + { + len = sprintf(f, "%d", width); + f += len; + } + if (!(flags & DOUBLE_RFLAG_NO_PRECISION)) + { + *f++ = '.'; + len = sprintf(f, "%d", precision); + f += len; + } + if ((flags & DOUBLE_RFLAG_EXCLUDE_F) && (flags & DOUBLE_RFLAG_EXCLUDE_A) && (flags & DOUBLE_RFLAG_EXCLUDE_E)) + { + flags |= DOUBLE_RFLAG_EXCLUDE_F; + } + while (1) + { + base = rand() % sizeof(baseArray); + if (((flags & DOUBLE_RFLAG_EXCLUDE_F) && (baseArray[base] == 'F' || baseArray[base] == 'f')) || + ((flags & DOUBLE_RFLAG_EXCLUDE_A) && (baseArray[base] == 'A' || baseArray[base] == 'a')) || + ((flags & DOUBLE_RFLAG_EXCLUDE_E) && (baseArray[base] == 'E' || baseArray[base] == 'e')) + ) continue; + break; + } + *f++ = baseArray[base]; + *f = '\0'; +} + +static int64_t uint64_cmp(uint64_t *v1, uint64_t *v2) +{ + int64_t error = *v1 - *v2; + if (error < 0) error = -error; + return error; +} + +static int double_equal(double *v1, double *v2) +{ + double_u *u1 = (double_u *)v1; + double_u *u2 = (double_u *)v2; + + // 都认作0,即为相等 + if (u1->exponent == 0 && u2->exponent == 0) return 1; + + // 允许一位舍入误差 + if (uint64_cmp(&u1->int_, &u2->int_) > 1) return 0; + + return 1; +} + +static void double_print(FILE *file, double value) +{ + double_u v = {.double_ = value}; + uint64_t mvalue = v.mantissa; + fprintf(file, "// [double]<%llu>(%u,%d,%llu){", (uint64_t)v.int_, (uint32_t)v.sign, (int32_t)((int32_t)v.exponent - 1023), (uint64_t)v.mantissa); + for (int i = 51; i >= 0; i--) + { + ((mvalue >> (i)) & 1) ? fputc('1', file) : fputc('0', file); + } + fprintf(file, "}\n"); +} + +/************************************************************************************/ +/************************************* Unit Test ************************************/ +/************************************************************************************/ + +// #define EXIT_TEST +extern uint64_t unitt_clock(void); + +static void generate_filename(char *filename, uint32_t size) +{ + time_t current_time = time(NULL); + if (current_time == ((time_t)-1)) + { + fprintf(stderr, "Failed to get current time\n"); + return; + } + + struct tm *local_time = localtime(¤t_time); + if (local_time == NULL) { + fprintf(stderr, "Failed to convert to local time\n"); + return; + } + + strftime(filename, size, "%Y%m%d_%H%M%S.txt", local_time); +} + +static FILE** error_file(int index) +{ + static FILE *table[6] = {NULL, NULL, NULL, NULL}; // stdout + FILE **file = NULL; + + index = index % 6; + file = &table[index]; + if (!*file) + { + char filename[64] = "built/"; + filename[6] = '0' + index; + filename[7] = '_'; + generate_filename(filename + 8, sizeof(filename) - 8); + *file = fopen(filename, "a"); + if (*file == NULL) + { + perror("Failed to open output file"); + return NULL; + } + } + + return file; +} + +static void error_record_cal(char op, floatl a, floatl b, floatl c, double x, double y, double z) +{ + FILE **file = NULL; + int index = 0; + + if (op == '+') index = 0; + else if (op == '-') index = 1; + else if (op == '*') index = 2; + else if (op == '/') index = 3; + + file = error_file(index); + + uint64_t m, n; + memcpy(&m, &a, sizeof(m)); + memcpy(&n, &b, sizeof(n)); + double_print(*file, x); + double_print(*file, y); + double_print(*file, z); + double_print(*file, *(double *)(&c)); + fprintf(*file, "{.v1.int_ = 0x%016llX, .v2.int_ = 0x%016llX}, // %lf %c %lf = %lf\n\n", m, n, x, op, y, z); +} + +static void error_record_print(floatl a, char *format, char *s1, char *s2) +{ + FILE **file = error_file(4); + + double_print(*file, *(double *)(&a)); + fprintf(*file, "// %s\n", format); + fprintf(*file, "// %s\n", s1); + fprintf(*file, "// %s\n", s2); + fprintf(*file, "\n\n"); +} + +static void error_record_from(floatl a, floatl b, char *format, char *s1, char *s2) +{ + FILE **file = error_file(5); + + double_print(*file, *(double *)(&a)); + double_print(*file, *(double *)(&b)); + fprintf(*file, "// %s\n", format); + fprintf(*file, "// %s\n", s1); + fprintf(*file, "// %s\n", s2); + fprintf(*file, "\n\n"); +} + +static int u_test_add(void) +{ + for (int i = 0; i < 1000; i++) + { + floatl a = floatl_random(); + floatl b = floatl_random(); + floatl c = FLOATL_CONST_0; + + double x = 0; + double y = 0; + double z = 0; + + memcpy(&x, &a, sizeof(x)); + memcpy(&y, &b, sizeof(y)); + + { c = floatl_add(a, b); z = x + y; } + + if (!double_equal(&c, &z)) + { + error_record_cal('+', a, b, c, x, y, z); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +static int u_test_sub(void) +{ + for (int i = 0; i < 1000; i++) + { + floatl a = floatl_random(); + floatl b = floatl_random(); + floatl c = FLOATL_CONST_0; + + double x = 0; + double y = 0; + double z = 0; + + memcpy(&x, &a, sizeof(x)); + memcpy(&y, &b, sizeof(y)); + + { c = floatl_sub(a, b); z = x - y; } + + if (!double_equal(&c, &z)) + { + error_record_cal('-', a, b, c, x, y, z); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +static int u_test_mul(void) +{ + for (int i = 0; i < 1000; i++) + { + floatl a = floatl_random(); + floatl b = floatl_random(); + floatl c = FLOATL_CONST_0; + + double x = 0; + double y = 0; + double z = 0; + + memcpy(&x, &a, sizeof(x)); + memcpy(&y, &b, sizeof(y)); + + { c = floatl_mul(a, b); z = x * y; } + + if (!double_equal(&c, &z)) + { + error_record_cal('*', a, b, c, x, y, z); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +static int u_test_div(void) +{ + for (int i = 0; i < 1000; i++) + { + floatl a = floatl_random(); + floatl b = floatl_random(); + floatl c = FLOATL_CONST_0; + + double x = 0; + double y = 0; + double z = 0; + + memcpy(&x, &a, sizeof(x)); + memcpy(&y, &b, sizeof(y)); + + if (fabs(y) < 1e-9) continue; + + { c = floatl_div(a, b); z = x / y; } + + if (!double_equal(&c, &z)) + { + error_record_cal('/', a, b, c, x, y, z); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +static int u_test_print(void) +{ + static char format[100] = {0}; + static char buffer_f[100] = {0}; + static char buffer_d[100] = {0}; + + for (int i = 0; i < 1000; i++) + { + floatl a = floatl_random(); + double x = 0; + int len_f = 0; + int len_d = 0; + + memcpy(&x, &a, sizeof(x)); + double_random_format(format, sizeof(format), DOUBLE_RFLAG_EXCLUDE_F | DOUBLE_RFLAG_EXCLUDE_A); + + len_f = floatl_print(a, buffer_f, sizeof(buffer_f), format); + len_d = snprintf(buffer_d, sizeof(buffer_d), format, x); + + if (len_f <= 0 || len_d <= 0) continue; + + if (len_f != len_d || strcmp(buffer_f, buffer_d) != 0) + { + error_record_print(a, format, buffer_f, buffer_d); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +static int u_test_from(void) +{ + static char format[100] = {0}; + static char buffer_0[100] = {0}; + static char buffer_1[100] = {0}; + + for (int i = 0; i < 1000; i++) + { + floatl a = floatl_random(); + floatl b = FLOATL_CONST_0; + + double_random_format(format, sizeof(format), DOUBLE_RFLAG_NO_PLUS | DOUBLE_RFLAG_NO_SUB | DOUBLE_RFLAG_NO_ZERO | DOUBLE_RFLAG_NO_WIDTH); + + if (floatl_print(a, buffer_0, sizeof(buffer_0), format) <= 0) continue; + + b = floatl_from(buffer_0); + + floatl_print(b, buffer_1, sizeof(buffer_1), format); + + if (floatl_isnan(b) || strncmp(buffer_0, buffer_1, sizeof(buffer_0))) + { + error_record_from(a, b, format, buffer_0, buffer_1); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +static void unitt_task(void) +{ + static UNITT_TCASE rand_tests[] = { +#if defined(FLOATL_USE_64BITS) + UNITT_TCASE(u_test_add), + UNITT_TCASE(u_test_sub), + UNITT_TCASE(u_test_mul), + UNITT_TCASE(u_test_div), + UNITT_TCASE(u_test_print), +#endif + UNITT_TCASE(u_test_from), + }; + + static UNITT suites[] = { + { "floatl suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock }, + }; + + UNITT_EXE(suites); +} + +/************************************************************************************/ +/************************************* Base Test ************************************/ +/************************************************************************************/ + +/*----------------------------------------------------------------------------------*/ +/* Generate configuration [START] */ +/*----------------------------------------------------------------------------------*/ + +typedef struct +{ + uint32_t buffer[256]; + + uint32_t FLOATL_BIT_PARTS; // bits + uint32_t FLOATL_U32_PARTS; // FLOATL_BIT_PARTS / 32 ---- FLOATL_BIT_PARTS >> 5 + uint32_t FLOATL_U16_PARTS; // FLOATL_BIT_PARTS / 16 ---- FLOATL_BIT_PARTS >> 4 + uint32_t FLOATL_EXP_BITS; // floatl_cfg_gen_exp(FLOATL_BIT_PARTS) + uint32_t FLOATL_MANT_BITS; // FLOATL_BIT_PARTS - FLOATL_EXP_BITS - 1 + uint32_t FLOATL_MANT_PARTS; // FLOATL_MANT_BITS / 32 ---- FLOATL_MANT_BITS >> 5 + uint32_t FLOATL_MANT_HIGH_BITS; // FLOATL_MANT_BITS % 32 ---- FLOATL_MANT_BITS & 0x1F + uint32_t FLOATL_EXP_MID_VALUE; // 2^(FLOATL_EXP_BITS-1) - 1 + uint32_t FLOATL_EXP_WHL_VALUE; // 2^(FLOATL_EXP_BITS) - 1 + + uint32_t FLOATL2_BIT_PARTS; // FLOATL_BIT_PARTS * 2 + uint32_t FLOATL2_U32_PARTS; // FLOATL2_BIT_PARTS / 32 ---- FLOATL2_BIT_PARTS >> 5 + uint32_t FLOATL2_U16_PARTS; // FLOATL2_BIT_PARTS / 16 ---- FLOATL2_BIT_PARTS >> 4 +} FLINFO; + +typedef struct +{ + uint32_t exp; + char *mantBin; +} FLCSTE; // const pow10(n) + +static FLCSTE fle_list[] = { + {.exp = 0, .mantBin = "0000000000000000000000000000000000000000000000000000"}, + {.exp = 3, .mantBin = "0100000000000000000000000000000000000000000000000000"}, + {.exp = 6, .mantBin = "1001000000000000000000000000000000000000000000000000"}, + {.exp = 9, .mantBin = "1111010000000000000000000000000000000000000000000000"}, + {.exp = 13, .mantBin = "0011100010000000000000000000000000000000000000000000"}, + {.exp = 16, .mantBin = "1000011010100000000000000000000000000000000000000000"}, + {.exp = 19, .mantBin = "1110100001001000000000000000000000000000000000000000"}, + {.exp = 23, .mantBin = "0011000100101101000000000000000000000000000000000000"}, + {.exp = 26, .mantBin = "0111110101111000010000000000000000000000000000000000"}, + {.exp = 29, .mantBin = "1101110011010110010100000000000000000000000000000000"}, + {.exp = 33, .mantBin = "0010101000000101111100100000000000000000000000000000"}, + {.exp = 36, .mantBin = "0111010010000111011011101000000000000000000000000000"}, + {.exp = 39, .mantBin = "1101000110101001010010100010000000000000000000000000"}, + {.exp = 43, .mantBin = "0010001100001001110011100101010000000000000000000000"}, + {.exp = 46, .mantBin = "0110101111001100010000011110100100000000000000000000"}, + {.exp = 49, .mantBin = "1100011010111111010100100110001101000000000000000000"}, +}; + +// e = 2.8625 * log2(bits) + 0.0111 * bits - 6.6730 +uint32_t floatl_cfg_gen_exp(uint32_t bits) +{ + const int y = bits; + int mantissa = 0; + int exponent = 0; + int sign = 1; + + for (int i = y; i > 0; i--) + { + if (log2(i) * 2 < (y - i - 1)) + { + mantissa = i + 1; + break; + } + } + exponent = bits - sign - mantissa; + + // printf("---------------- %d\r\n", bits); + // printf("mantissa %d\r\n", mantissa); + // printf("exponent %d\r\n", exponent); + // printf("sign %d\r\n", sign); + + // printf("high %d\r\n", mantissa & 0x1F); // % 32 + // printf("part %d\r\n", mantissa >> 5); // / 32 + + if (exponent >= 31) return 0; + + return exponent; +} + +void floatl_cfg_const_out(FILE* file, FLINFO *info) +{ + if (!file || !info) return; + + fprintf(file, "(floatl){.u32={"); + for (int i = 0; i < info->FLOATL_U32_PARTS; i++) + { + uint32_t value = info->buffer[i]; + if (value == 0) fprintf(file, "0,"); + else if (value == 0xFFFFFFFF) fprintf(file, "-1,"); + else fprintf(file, "0x%08X,", value); + } + fprintf(file, "}}\n"); +} + +FLINFO *floatl_cfg_set_sign(FLINFO *info, int sign) +{ + if (sign) info->buffer[info->FLOATL_U32_PARTS - 1] |= (1 << 31); + else info->buffer[info->FLOATL_U32_PARTS - 1] &= ~(1 << 31); + return info; +} + +FLINFO *floatl_cfg_set_exp_real(FLINFO *info, uint32_t t) +{ + uint32_t temp = 1; + + temp <<= info->FLOATL_EXP_BITS; + temp -= 1; + + t &= temp; + t <<= (32 - info->FLOATL_EXP_BITS - 1); + + temp <<= (32 - info->FLOATL_EXP_BITS - 1); + + + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~temp); // clear + + info->buffer[info->FLOATL_U32_PARTS - 1] |= t; + + return info; +} + +FLINFO *floatl_cfg_set_exp(FLINFO *info, int32_t e) +{ + return floatl_cfg_set_exp_real(info, e + info->FLOATL_EXP_MID_VALUE); +} + +FLINFO *floatl_cfg_set_mant(FLINFO *info, char *bin) +{ + char *s = bin; + + while (*s) + { + int index = info->FLOATL_MANT_BITS - (s - bin) - 1; + if (index < 0) break; + if (index >= 0 && *s == '1') + { + int part = index / 32; + int bit = index % 32; + + info->buffer[part] |= (1 << bit); + } + s++; + } + + return info; +} + +FLINFO *floatl_cfg_int_zero(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + return info; +} + +FLINFO *floatl_cfg_const_0(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + return info; +} + +FLINFO *floatl_cfg_const_1(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + info->buffer[info->FLOATL_U32_PARTS - 1] &= 0xBFFFFFFF; + + return info; +} + +FLINFO *floatl_cfg_const_1eX(FLINFO *info, uint32_t e) +{ + if (e >= sizeof(fle_list) / sizeof(fle_list[0])) return NULL; + + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp(info, fle_list[e].exp); + floatl_cfg_set_mant(info, fle_list[e].mantBin); + + return info; +} + +FLINFO *floatl_cfg_inf(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + + return info; +} + +FLINFO *floatl_cfg_nan(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + info->buffer[info->FLOATL_U32_PARTS - 1] |= 0x80000000; + + return info; +} + +FLINFO *floatl_cfg_all_sign(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + info->buffer[info->FLOATL_U32_PARTS - 1] |= 0x80000000; + + return info; +} + +FLINFO *floatl_cfg_all_exp(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0xFFFFFFFF); + + return info; +} + +FLINFO *floatl_cfg_all_mant(FLINFO *info) +{ + memset(info->buffer, -1, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 0); + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~0x80000000); + + return info; +} + +FLINFO *floatl_cfg_all_exp_mant(FLINFO *info) +{ + memset(info->buffer, -1, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~0x80000000); + + return info; +} + +FLINFO *floatl_cfg_hide_mant_bit(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 1); + + return info; +} + +FLINFO *floatl_cfg_mant_plus_max(FLINFO *info) +{ + memset(info->buffer, 0, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 8); + + return info; +} + +FLINFO *floatl_cfg_mant_whole(FLINFO *info) +{ + memset(info->buffer, -1, info->FLOATL_U32_PARTS * sizeof(uint32_t)); + + floatl_cfg_set_exp_real(info, 1); + info->buffer[info->FLOATL_U32_PARTS - 1] &= (~0x80000000); + + return info; +} + +void floatl_cfg_generate(uint32_t bits, const char *filename) +{ + #define MINBITS 64 + #define NEWLINE "\n" // "\r\n" // + + FILE* output = stdout; // Default output to standard output + if (filename != NULL) + { + output = fopen(filename, "w"); + if (output == NULL) + { + fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE); + return; + } + } + + /* The number of bits in an floatl needs to be an exponent of two */ + if ((bits & (bits - 1)) != 0) + { + fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE); + return; + } + + /* Limiting the minimum bit */ + if (bits < MINBITS) + { + fprintf(stdout, "[ERROR] `bits` too small\r\b"); + return; + } + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config start */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == MINBITS) + { + fprintf(output, "#define FLOATL_USE_%uBITS"NEWLINE, tb); + } + else + { + fprintf(output, "// #define FLOATL_USE_%uBITS"NEWLINE, tb); + } + } + fprintf(output, NEWLINE); + + floatl temp; + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == MINBITS) + { + fprintf(output, "#if defined(FLOATL_USE_%uBITS)"NEWLINE, tb); + } + else + { + fprintf(output, "#elif defined(FLOATL_USE_%uBITS)"NEWLINE, tb); + } + + FLINFO info; + info.FLOATL_BIT_PARTS = tb; + info.FLOATL_U32_PARTS = info.FLOATL_BIT_PARTS >> (5); + info.FLOATL_U16_PARTS = info.FLOATL_BIT_PARTS >> (4); + info.FLOATL_EXP_BITS = floatl_cfg_gen_exp(info.FLOATL_BIT_PARTS); + info.FLOATL_MANT_BITS = info.FLOATL_BIT_PARTS - info.FLOATL_EXP_BITS - 1; + info.FLOATL_MANT_PARTS = info.FLOATL_MANT_BITS >> 5; + info.FLOATL_MANT_HIGH_BITS = info.FLOATL_MANT_BITS & 0x1F; + info.FLOATL_EXP_MID_VALUE = (uint32_t)pow(2, info.FLOATL_EXP_BITS - 1) - 1; + info.FLOATL_EXP_WHL_VALUE = (uint32_t)pow(2, info.FLOATL_EXP_BITS) - 1; + info.FLOATL2_BIT_PARTS = info.FLOATL_BIT_PARTS * 2; + info.FLOATL2_U32_PARTS = info.FLOATL2_BIT_PARTS >> (5); + info.FLOATL2_U16_PARTS = info.FLOATL2_BIT_PARTS >> (4); + + fprintf(output, "#define __FLOATL_BIT_PARTS__ %u"NEWLINE, info.FLOATL_BIT_PARTS ); + fprintf(output, "#define __FLOATL_U32_PARTS__ %u"NEWLINE, info.FLOATL_U32_PARTS ); + fprintf(output, "#define __FLOATL_U16_PARTS__ %u"NEWLINE, info.FLOATL_U16_PARTS ); + fprintf(output, "#define __FLOATL_EXP_BITS__ %u"NEWLINE, info.FLOATL_EXP_BITS ); + fprintf(output, "#define __FLOATL_MANT_BITS__ %u"NEWLINE, info.FLOATL_MANT_BITS ); + fprintf(output, "#define __FLOATL_MANT_PARTS__ %u"NEWLINE, info.FLOATL_MANT_PARTS ); + fprintf(output, "#define __FLOATL_MANT_HIGH_BITS__ %u"NEWLINE, info.FLOATL_MANT_HIGH_BITS ); + fprintf(output, "#define __FLOATL_EXP_MID_VALUE__ %u"NEWLINE, info.FLOATL_EXP_MID_VALUE ); + fprintf(output, "#define __FLOATL_EXP_WHL_VALUE__ %u"NEWLINE, info.FLOATL_EXP_WHL_VALUE ); + + fprintf(output, "#define __FLOATL2_BIT_PARTS__ %u"NEWLINE, info.FLOATL2_BIT_PARTS ); + fprintf(output, "#define __FLOATL2_U32_PARTS__ %u"NEWLINE, info.FLOATL2_U32_PARTS ); + fprintf(output, "#define __FLOATL2_U16_PARTS__ %u"NEWLINE, info.FLOATL2_U16_PARTS ); + + fprintf(output, "#define __FLOATL_CONST_0__ "); floatl_cfg_const_out(output, floatl_cfg_const_0(&info) ); + fprintf(output, "#define __FLOATL_CONST_1__ "); floatl_cfg_const_out(output, floatl_cfg_const_1(&info) ); + fprintf(output, "#define __FLOATL_CONST_1e0__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,0) ); + fprintf(output, "#define __FLOATL_CONST_1e1__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,1) ); + fprintf(output, "#define __FLOATL_CONST_1e2__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,2) ); + fprintf(output, "#define __FLOATL_CONST_1e3__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,3) ); + fprintf(output, "#define __FLOATL_CONST_1e4__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,4) ); + fprintf(output, "#define __FLOATL_CONST_1e5__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,5) ); + fprintf(output, "#define __FLOATL_CONST_1e6__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,6) ); + fprintf(output, "#define __FLOATL_CONST_1e7__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,7) ); + fprintf(output, "#define __FLOATL_CONST_1e8__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,8) ); + fprintf(output, "#define __FLOATL_CONST_1e9__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,9) ); + fprintf(output, "#define __FLOATL_CONST_1e10__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,10) ); + fprintf(output, "#define __FLOATL_CONST_1e11__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,11) ); + fprintf(output, "#define __FLOATL_CONST_1e12__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,12) ); + fprintf(output, "#define __FLOATL_CONST_1e13__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,13) ); + fprintf(output, "#define __FLOATL_CONST_1e14__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,14) ); + fprintf(output, "#define __FLOATL_CONST_1e15__ "); floatl_cfg_const_out(output, floatl_cfg_const_1eX(&info,15) ); + fprintf(output, "#define __FLOATL_INT_ZERO__ "); floatl_cfg_const_out(output, floatl_cfg_int_zero(&info) ); + fprintf(output, "#define __FLOATL_INF__ "); floatl_cfg_const_out(output, floatl_cfg_inf(&info) ); + fprintf(output, "#define __FLOATL_NAN__ "); floatl_cfg_const_out(output, floatl_cfg_nan(&info) ); + fprintf(output, "#define __FLOATL_ALL_SIGN__ "); floatl_cfg_const_out(output, floatl_cfg_all_sign(&info) ); + fprintf(output, "#define __FLOATL_ALL_EXP__ "); floatl_cfg_const_out(output, floatl_cfg_all_exp(&info) ); + fprintf(output, "#define __FLOATL_ALL_MANT__ "); floatl_cfg_const_out(output, floatl_cfg_all_mant(&info) ); + fprintf(output, "#define __FLOATL_ALL_EXP_MANT__ "); floatl_cfg_const_out(output, floatl_cfg_all_exp_mant(&info) ); + fprintf(output, "#define __FLOATL_HIDE_MANT_BIT__ "); floatl_cfg_const_out(output, floatl_cfg_hide_mant_bit(&info) ); + fprintf(output, "#define __FLOATL_MANT_PLUS_MAX__ "); floatl_cfg_const_out(output, floatl_cfg_mant_plus_max(&info) ); + fprintf(output, "#define __FLOATL_MANT_WHL__ "); floatl_cfg_const_out(output, floatl_cfg_mant_whole(&info) ); + } + + fprintf(output, "#endif"NEWLINE); + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config end */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + 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 `FLOATL_MAX_DEC`\r\n"); + } + else + { + printf("[INFO] The configuration has been generated, copy it to the `floatl_cfg.h` range specified\r\n"); + } + + return 0; +} + +/*----------------------------------------------------------------------------------*/ +/* Generate configuration [END] */ +/*----------------------------------------------------------------------------------*/ + +static void test_error() +{ + double d1 = 123.456; + double d2 = 999.365; + double d3 = d1 + d2; + + floatl f1 = floatl(d1); + floatl f2 = floatl(d2); + floatl f3 = floatl_add(f1, f2); + + printf("----------------\r\n"); + double a = 0x8.153800p-134; + printf("a: %a\r\n", a); // print 0x1.02a700p-131 + snprintf(buffer, sizeof(buffer), "%a", a); + printf("b: %s\r\n", buffer); // print 0x8.1538p-134 + // why? + + // double_print(stdout, d1); + // printf("double_from_string %f\r\n", double_from_string("123.456")); + // printf("double_from_string %e\r\n", double_from_string("1.23456e+2")); + // printf("double_from_string %a\r\n", double_from_string("0x1.23456p+2")); + + printf("%020a\r\n", d1); + printf("%s\r\n", floatl_show(f1, buffer, sizeof(buffer), "020a")); + printf("from %s\r\n", floatl_show(floatl_from("123.456"), buffer, sizeof(buffer), "%f")); + printf("from %s\r\n", floatl_show(floatl_from("1.23456e+2"), buffer, sizeof(buffer), "%e")); + + printf("------------\r\n"); + d1 = 0x1.43a2073p+1; + printf("%020e\r\n", d1); + printf("%s\r\n", floatl_show(floatl_from("0x1.43a2073p+1"), buffer, sizeof(buffer), "%020e")); + + if (memcmp(&d3, &f3, sizeof(d3))) + { + double_print(stdout, d1); + double_print(stdout, d2); + double_print(stdout, d3); + double_print(stdout, *(double *)(&f3)); + } +} + +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)); +} + +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")); +} + +static void test_calculate(void) +{ + floatl a = floatl_from("123456789.123456789"); + floatl b = floatl_from("987654321.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("b / a: %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)); +} + +static void test_base(void) +{ + float s1 = 12.625; + float s2 = 16.456; + double d1 = 12.625; + double d2 = 16.456; + floatl f1 = floatl_from_d(d1); + floatl f2 = floatl_from_d(d2); + + float s; + double d; + floatl f; + float temp; + + printf("==============================================\r\n"); + printf("==================== + =======================\r\n"); + printf("==============================================\r\n"); + + s = s1 + s2; + d = d1 + d2; + f = floatl_add(f1, f2); + + float_show_raw(s); + double_show_raw(d); + floatl_show_raw(f, 0, 0, 0); + + printf("==============================================\r\n"); + printf("==================== - =======================\r\n"); + printf("==============================================\r\n"); + + s = s1 - s2; + d = d1 - d2; + f = floatl_sub(f1, f2); + + float_show_raw(s); + double_show_raw(d); + floatl_show_raw(f, 0, 0, 0); + + printf("==============================================\r\n"); + printf("==================== * =======================\r\n"); + printf("==============================================\r\n"); + + s = s1 * s2; + d = d1 * d2; + f = floatl_mul(f1, f2); + + float_show_raw(s); + double_show_raw(d); + floatl_show_raw(f, 0, 0, 0); + + printf("==============================================\r\n"); + printf("==================== / =======================\r\n"); + printf("==============================================\r\n"); + + s = s1 / s2; + d = d1 / d2; + f = floatl_div(f1, f2); + + float_show_raw(s); + double_show_raw(d); + floatl_show_raw(f, 0, 0, 0); + + // float l1 = 1.0f; + // showBits(&l1, sizeof(l1)); + +#if 0 + // float_show_raw(0.0f); + // float_show_raw(1.0f); + + // double y = 11.6250; + // int e = 0; + // double_show_raw(y); + // y = frexp(y, &e); + // double_show_raw(y); + // printf("y %f e %d\r\n", y, e); +#endif +} + +/************************************************************************************/ +/************************************* Command ************************************/ +/************************************************************************************/ + +static void usage(void) +{ + printf( +"Usage: floatl [opt] [arg] ...\n" +"\n" +"options:\n" +" -e Specifies the function to execute, the default is the test\n" +" Test base function\n" +" Unit test\n" +" Test define function\n" +" Calculate string math expression\n" +" Generate the floatl configuration file code segment, need specify -f -b\n" +" Print an floatl number\n" +" Function that tests for floatl errors\n" +" -l Format string, 10d, 08x, ...\n" +" -o Operate function, add, sub, mul, div, ...\n" +" -n floatl number expression\n" +" -f File name, temporarily store configuration code segment\n" +" -b Maximum number of configured bits\n" +" -h Print help\n" +" -v Print version\n" +" -u [] Unit test period, unit ms, the default is 1000ms\n" +"\n" + + ); +} + +static int test(int argc, char *argv[]) +{ + char *execute = NULL; + int ut_period = 1000; + char *filename = NULL; + int bits = 0; + + /* reset getopt */ + command_opt_init(); + + while (1) + { + int opt = command_getopt(argc, argv, "e:hvu::f:b:n:o:l:"); + if (opt == -1) break; + + switch (opt) + { + case 'b' : + bits = atoi(command_optarg); + break; + case 'f' : + filename = command_optarg; + break; + case 'u' : + if (command_optarg) ut_period = atoi(command_optarg); + break; + case 'e' : + execute = command_optarg; + break; + case 'v' : + printf("floatl version %d.%d.%d\r\n", FLOATL_V_MAJOR, FLOATL_V_MINOR, FLOATL_V_PATCH); + return 0; + case '?': + printf("Unknown option `%c`\r\n", command_optopt); + return -1; + case 'h' : + default: + usage(); + return 0; + } + } + + if (execute) + { + if (!strcmp(execute, "base")) + { + test_base(); + } + else if (!strcmp(execute, "ut")) + { + srand((uint32_t)time(NULL)); + #if defined(TEST_TARGET_floatl) + while (1) + { + unitt_task(); + usleep(1000 * ut_period); + } + #else + printf("create task %d\r\n", task_create(ut_period, unitt_task)); + #endif + } + else if (!strcmp(execute, "define")) + { + test_define(); + } + else if (!strcmp(execute, "gen")) + { + floatl_cfg_generate(bits, filename); + } + else if (!strcmp(execute, "cal")) + { + test_calculate(); + } + else if (!strcmp(execute, "print")) + { + test_print(); + } + else if (!strcmp(execute, "error")) + { + test_error(); + } + } + else + { + test_base(); + } + + return 0; +} + +/************************************************************************************/ +/************************************ Test entry ************************************/ +/************************************************************************************/ + +#if defined(TEST_TARGET_floatl) +int main(int argc, char *argv[]) +{ + return test(argc, argv); +} +#else +void test_floatl(void) +{ + command_export("floatl", test); +} +init_export_app(test_floatl); +#endif diff --git a/test/test_intl.c b/test/test_intl.c index 2a9c4ef..b9db645 100644 --- a/test/test_intl.c +++ b/test/test_intl.c @@ -12,6 +12,8 @@ #include "intl.h" #endif +static char pbuff[INTL_PRINT_MAX] = {0}; + /************************************************************************************/ /************************************* Unit Test ************************************/ /************************************************************************************/ @@ -19,13 +21,86 @@ // #define EXIT_TEST extern uint64_t unitt_clock(void); -static int test_0(void) +static intl random_intl() +{ + intl random = INTL_ZERO; + + for (int i = 0; i < __INTL_U32_PARTS__; i++) + { + random.u32[i] = rand(); + } + + return random; +} + +static const char* random_format() +{ + const char *format[4] = { "d", "#b", "#o", "#x" }; + return format[rand() % 4]; +} + +static int test_convert(void) { for (int i = 0; i < 100; i++) { - if (0) + intl src = random_intl(); + intl dst = intl_from(intl_show(src, pbuff, sizeof(pbuff), random_format())); + + if (!intl_eq(src, dst)) { - + printf("convert fail: \r\n"); + printf("src: %s\r\n", intl_show(src, pbuff, sizeof(pbuff), "x")); + printf("dst: %s\r\n", intl_show(dst, pbuff, sizeof(pbuff), "x")); + #if defined (EXIT_TEST) + exit(0); + #endif + return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +/* Need config intl as 64bits */ +static int test_accuracy(void) +{ + for (int i = 0; i < 1000; i++) + { + int op = rand() % 10; + uint8_t sh = 0; + + intl a = random_intl(); + intl b = random_intl(); + intl c = INTL_ZERO; + + int64_t x = 0; + int64_t y = 0; + int64_t z = 0; + + memcpy(&x, &a, sizeof(x)); + memcpy(&y, &b, sizeof(y)); + + /* Skip the division by 0 */ + if (op == 3 && y == 0) continue; + /* Adjust shift */ + if (op == 8 || op == 9) { sh = y; sh %= 64; } + + if (op == 0) { c = intl_add(a, b); z = x + y; } + else if (op == 1) { c = intl_sub(a, b); z = x - y; } + else if (op == 2) { c = intl_mul(a, b); z = x * y; } + else if (op == 3) { c = intl_div(a, b); z = x / y; } + else if (op == 4) { c = intl_mod(a, b); z = x % y; } + else if (op == 5) { c = intl_and(a, b); z = x & y; } + else if (op == 6) { c = intl_xor(a, b); z = x ^ y; } + else if (op == 7) { c = intl_or (a, b); z = x | y; } + else if (op == 8) { c = intl_shl(a, sh); z = x << sh; } + else if (op == 9) { c = intl_shr(a, sh); z = x >> sh; } + + if (memcmp(&c, &z, sizeof(z)) != 0) + { + printf("accuracy fail: %d,%d\r\n", op, sh); + printf("c: %s\r\n", intl_show(c, pbuff, sizeof(pbuff), "d")); + printf("z: %lld\r\n", z); #if defined (EXIT_TEST) exit(0); #endif @@ -39,13 +114,14 @@ static int test_0(void) static void unitt_task(void) { static UNITT_TCASE rand_tests[] = { - UNITT_TCASE(test_0), - // UNITT_TCASE(test_1), - // UNITT_TCASE(test_2), + UNITT_TCASE(test_convert), +#if defined (INTL_USE_64BITS) + UNITT_TCASE(test_accuracy), +#endif }; static UNITT suites[] = { - { "xxx suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock }, + { "intl suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock }, }; UNITT_EXE(suites); @@ -55,16 +131,141 @@ static void unitt_task(void) /************************************* Base Test ************************************/ /************************************************************************************/ -#define INTL_P_DEC 0x01 -#define INTL_P_BIN 0x02 -#define INTL_P_HEX 0x04 - -static void print_intl(intl a, uint8_t type) +void intl_gen_cfg(uint32_t bits, const char *filename) { - 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)); + #define MINBITS 64 + #define NEWLINE "\n" // "\r\n" // + + FILE* output = stdout; // Default output to standard output + if (filename != NULL) + { + output = fopen(filename, "w"); + if (output == NULL) + { + fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE); + return; + } + } + + /* The number of bits in an intl needs to be an exponent of two */ + if ((bits & (bits - 1)) != 0) + { + fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE); + return; + } + + /* Limiting the minimum bit */ + if (bits < MINBITS) + { + fprintf(stdout, "[ERROR] `bits` too small\r\b"); + return; + } + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config start */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == bits) + { + fprintf(output, "#define INTL_USE_%uBITS"NEWLINE, tb); + } + else + { + fprintf(output, "// #define INTL_USE_%uBITS"NEWLINE, tb); + } + } + fprintf(output, ""NEWLINE); + + intl temp; + + for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) + { + if (tb == MINBITS) + { + fprintf(output, "#if defined(INTL_USE_%uBITS)"NEWLINE, tb); + } + else + { + fprintf(output, "#elif defined(INTL_USE_%uBITS)"NEWLINE, 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 + 3; // "0b" + '\0' + MAX_DEC = MAX_BIN; // First apply as MAX bin maximum value, and then according to the actual calculation + MAX_HEX = (BIT_PARTS >> (2)) + 3; // "0x" + '\0' + + /* The current configuration is applied */ + if (sizeof(temp) == (bits >> 3)) + { + char buffer[__INTL_P_MAX_BIN__]; + MAX_DEC = intl_print(intl_shl(intl(1), BIT_PARTS - 1), buffer, sizeof(buffer), "d") + 1; // '\0' + } + + fprintf(output, "#define __INTL_BIT_PARTS__ %u"NEWLINE, BIT_PARTS); + fprintf(output, "#define __INTL_U32_PARTS__ %u"NEWLINE, U32_PARTS); + fprintf(output, "#define __INTL_U16_PARTS__ %u"NEWLINE, U16_PARTS); + fprintf(output, "#define __INTL_P_MAX_BIN__ %u"NEWLINE, MAX_BIN); + fprintf(output, "#define __INTL_P_MAX_DEC__ %u"NEWLINE, MAX_DEC); + fprintf(output, "#define __INTL_P_MAX_HEX__ %u"NEWLINE, MAX_HEX); + + /* __INTL_MAX__ */ + fprintf(output, "#define __INTL_MAX__ (intl){.u32={"); + for (uint32_t i = 0; i < U32_PARTS; i++) + { + fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x7FFFFFFF" : "-1"); + } + fprintf(output, "}}"NEWLINE); + + /* __INTL_MIN__ */ + fprintf(output, "#define __INTL_MIN__ (intl){.u32={"); + for (uint32_t i = 0; i < U32_PARTS; i++) + { + fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x80000000" : "0"); + } + fprintf(output, "}}"NEWLINE); + + /* __INTL_ZERO__ */ + fprintf(output, "#define __INTL_ZERO__ (intl){.u32={"); + for (uint32_t i = 0; i < U32_PARTS; i++) + { + fprintf(output, "0,"); + } + fprintf(output, "}}"NEWLINE); + } + + fprintf(output, "#endif"NEWLINE); + + fprintf(output, "/*****************************************************************/"NEWLINE); + fprintf(output, "/* Config end */"NEWLINE); + fprintf(output, "/*****************************************************************/"NEWLINE); + + fprintf(stdout, "\r\n\r\n-------------------------------------------------------------\r\n"NEWLINE); + + /* The current configuration is not applied */ + if (sizeof(temp) != (bits >> 3)) + { + fprintf(stdout, "[TODO][%s] Apply the current configuration and run it again to get the new `__INTL_P_MAX_DEC__`"NEWLINE, filename); + } + else + { + fprintf(stdout, "[INFO][%s] The configuration has been generated, copy it to the `intl_cfg.h` range specified"NEWLINE, filename); + } + + if (filename != NULL) + { + fclose(output); + } } static void test_define(void) @@ -91,9 +292,23 @@ 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); + printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "dx")); + printf("a: %s\r\n", intl_show(INTL_ZERO, pbuff, sizeof(pbuff), "#x")); + printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "#o")); + printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "#x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "10x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "010x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "-10x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "-010x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#10x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#010x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#-10x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#-010x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#x")); + printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#0x")); + printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "#d")); + printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "#10d")); + printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "-#d")); } static void test_calculate(void) @@ -101,51 +316,27 @@ 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); + printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "d")); + printf("b: %s\r\n", intl_show(b, pbuff, sizeof(pbuff), "d")); + printf("a + b: %s\r\n", intl_show(intl_add(a, b), pbuff, sizeof(pbuff), "d")); + printf("a - b: %s\r\n", intl_show(intl_sub(a, b), pbuff, sizeof(pbuff), "d")); + printf("a * b: %s\r\n", intl_show(intl_mul(a, b), pbuff, sizeof(pbuff), "d")); + printf("b / a: %s\r\n", intl_show(intl_div(a, b), pbuff, sizeof(pbuff), "d")); + printf("b %% a: %s\r\n", intl_show(intl_mod(a, b), pbuff, sizeof(pbuff), "d")); + printf("a & b: %s\r\n", intl_show(intl_and(a, b), pbuff, sizeof(pbuff), "d")); + printf("a | b: %s\r\n", intl_show(intl_or(a, b), pbuff, sizeof(pbuff), "d")); + printf("a ^ b: %s\r\n", intl_show(intl_xor(a, b), pbuff, sizeof(pbuff), "d")); + printf("~a: %s\r\n", intl_show(intl_not(a), pbuff, sizeof(pbuff), "d")); + printf("a << 1: %s\r\n", intl_show(intl_shl(a, 1), pbuff, sizeof(pbuff), "d")); + printf("b >> 1: %s\r\n", intl_show(intl_shr(a, 1), pbuff, sizeof(pbuff), "d")); + printf("a++: %s\r\n", intl_show(intl_inc(a), pbuff, sizeof(pbuff), "d")); + printf("b--: %s\r\n", intl_show(intl_dec(a), pbuff, sizeof(pbuff), "d")); + printf("a > b: %d\r\n", intl_gt(a, b)); + printf("a >= b: %d\r\n", intl_ge(a, b)); + printf("a < b: %d\r\n", intl_lt(a, b)); + printf("a <= b: %d\r\n", intl_le(a, b)); + printf("a == b: %d\r\n", intl_eq(a, b)); + printf("a != b: %d\r\n", intl_ne(a, b)); } static void test_base(void) @@ -168,6 +359,15 @@ static void usage(void) " -e Specifies the function to execute, the default is the test\n" " Test base function\n" " Unit test\n" +" Test define function\n" +" Calculate string math expression\n" +" Generate the intl configuration file code segment, need specify -f -b\n" +" Print an intl number\n" +" -l Format string, 10d, 08x, ...\n" +" -o Operate function, add, sub, mul, div, ...\n" +" -n intl number expression\n" +" -f File name, temporarily store configuration code segment\n" +" -b Maximum number of configured bits\n" " -h Print help\n" " -v Print version\n" " -u [] Unit test period, unit ms, the default is 1000ms\n" @@ -180,17 +380,39 @@ static int test(int argc, char *argv[]) { char *execute = NULL; int ut_period = 1000; + char *filename = NULL; + int bits = 0; + + intl n[2] = {INTL_ZERO, INTL_ZERO}; + int in = 0; + char *op = NULL; + char *format = NULL; /* reset getopt */ command_opt_init(); while (1) { - int opt = command_getopt(argc, argv, "e:hvu::"); + int opt = command_getopt(argc, argv, "e:hvu::f:b:n:o:l:"); if (opt == -1) break; switch (opt) { + case 'l' : + format = command_optarg; + break; + case 'o' : + op = command_optarg; + break; + case 'n' : + if (in < 2) n[in++] = intl_from(command_optarg); + break; + case 'b' : + bits = atoi(command_optarg); + break; + case 'f' : + filename = command_optarg; + break; case 'u' : if (command_optarg) ut_period = atoi(command_optarg); break; @@ -229,6 +451,36 @@ static int test(int argc, char *argv[]) printf("create task %d\r\n", task_create(ut_period, unitt_task)); #endif } + else if (!strcmp(execute, "define")) + { + test_define(); + } + else if (!strcmp(execute, "gen")) + { + intl_gen_cfg(bits, filename); + } + else if (!strcmp(execute, "cal")) + { + intl result = INTL_ZERO; + + if (!strcmp(op, "add")) result = intl_add(n[0], n[1]); + else if (!strcmp(op, "sub")) result = intl_sub(n[0], n[1]); + else if (!strcmp(op, "mul")) result = intl_mul(n[0], n[1]); + else if (!strcmp(op, "div")) result = intl_div(n[0], n[1]); + else if (!strcmp(op, "mod")) result = intl_mod(n[0], n[1]); + else if (!strcmp(op, "and")) result = intl_and(n[0], n[1]); + else if (!strcmp(op, "xor")) result = intl_xor(n[0], n[1]); + else if (!strcmp(op, "or")) result = intl_or(n[0], n[1]); + else if (!strcmp(op, "shl")) result = intl_shl(n[0], *(uint32_t *)(&n[1])); + else if (!strcmp(op, "shr")) result = intl_shr(n[0], *(uint32_t *)(&n[1])); + else printf("No such function!\r\n"); + + printf("result: %s\r\n", intl_show(result, pbuff, sizeof(pbuff), "d")); + } + else if (!strcmp(execute, "print")) + { + printf("%s\r\n", intl_show(n[0], pbuff, sizeof(pbuff), format)); + } } else {