varch/test/test_floatl.c
Lamdonn fa4bd85f2e 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
2025-03-04 11:15:49 +08:00

1471 lines
44 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <float.h>
#if defined(TEST_TARGET_floatl)
#include <varch/command.h>
#include <varch/unitt.h>
#include <varch/floatl.h>
#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(&current_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 <execute> Specifies the function to execute, the default is the <base> test\n"
" <base> Test base function\n"
" <ut> Unit test\n"
" <define> Test define function\n"
" <cal> Calculate string math expression\n"
" <gen> Generate the floatl configuration file code segment, need specify -f -b\n"
" <print> Print an floatl number\n"
" <error> Function that tests for floatl errors\n"
" -l <format> Format string, 10d, 08x, ...\n"
" -o <op function> Operate function, add, sub, mul, div, ...\n"
" -n <floatl> floatl number expression\n"
" -f <filename> File name, temporarily store configuration code segment\n"
" -b <bits> Maximum number of configured bits\n"
" -h Print help\n"
" -v Print version\n"
" -u [<period>] 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