#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_; } float double_to_float(double d) { // 联合体用于直接操作二进制位 union { double d; uint64_t u; } du = { .d = d }; union { float f; uint32_t u; } fu; // 提取double的符号、指数、尾数 uint64_t sign = (du.u >> 63) & 0x1; int64_t exp = ((du.u >> 52) & 0x7FF) - 1023; // 原始指数 uint64_t mant = du.u & 0x000FFFFFFFFFFFFF; // 52位尾数 // 特殊值处理(NaN/Inf) if (exp == 1024) { fu.u = (sign << 31) | 0x7F800000 | (mant ? 0x7FFFFF : 0); return fu.f; } // 调整指数到float范围(-126~127) exp += 127; // 转换为float偏置指数 if (exp > 255) { // 上溢返回无穷大 fu.u = (sign << 31) | 0x7F800000; return fu.f; } else if (exp < 0) { // 下溢返回0 fu.u = sign << 31; return fu.f; } // 尾数处理(隐含的1 + 52位尾数) uint64_t extended_mant = mant | 0x0010000000000000; // 恢复隐含的1 uint32_t float_mant = (extended_mant >> 29); // 保留高23位 // 舍入处理(检查第29位) uint32_t round_bits = extended_mant & 0x1FFFFFFF; if (round_bits > 0x10000000 || (round_bits == 0x10000000 && (float_mant & 0x1))) { float_mant += 1; if (float_mant & 0x00800000) { // 尾数进位导致指数进位 float_mant >>= 1; exp += 1; if (exp > 255) { // 指数二次上溢 fu.u = (sign << 31) | 0x7F800000; return fu.f; } } } // 组合结果 fu.u = (sign << 31) | (exp << 23) | (float_mant & 0x007FFFFF); return fu.f; } // 将 double 的二进制表示转换为 uint64_t typedef unsigned long long uint64_t; typedef long long int64_t; uint64_t double_to_bits(double x) { return *((uint64_t*)&x); } double bits_to_double(uint64_t bits) { return *((double*)&bits); } // double_ceil 实现 double double_ceil(double x) { uint64_t bits = double_to_bits(x); int64_t exponent = ((bits >> 52) & 0x7FF) - 1023; if (exponent < 0) { // 如果指数为负,说明 x 在 (-1, 1) 之间 if (x > 0) { return 1.0; } else if (x == 0.0) { return 0.0; } else { return -0.0; } } int shift = 52 - exponent; if (shift <= 0) { // 如果 x 已经是整数,直接返回 x return x; } uint64_t mask = (1ULL << shift) - 1; uint64_t truncated = bits & ~mask; double result = bits_to_double(truncated); if (result < x) { result += 1.0; } return result; } // double_floor 实现 double double_floor(double x) { uint64_t bits = double_to_bits(x); int64_t exponent = ((bits >> 52) & 0x7FF) - 1023; if (exponent < 0) { // 如果指数为负,说明 x 在 (-1, 1) 之间 if (x >= 0) { return 0.0; } else { return -1.0; } } int shift = 52 - exponent; if (shift <= 0) { // 如果 x 已经是整数,直接返回 x return x; } uint64_t mask = (1ULL << shift) - 1; uint64_t truncated = bits & ~mask; double result = bits_to_double(truncated); if (result > x) { result -= 1.0; } return result; } // double_round 实现 double double_round(double x) { uint64_t bits = double_to_bits(x); int64_t exponent = ((bits >> 52) & 0x7FF) - 1023; if (exponent < 0) { // 如果指数为负,说明 x 在 (-1, 1) 之间 if (x > 0) { return (x >= 0.5) ? 1.0 : 0.0; } else { return (x <= -0.5) ? -1.0 : -0.0; } } int shift = 52 - exponent; if (shift <= 0) { // 如果 x 已经是整数,直接返回 x return x; } uint64_t mask = (1ULL << shift) - 1; uint64_t truncated = bits & ~mask; double result = bits_to_double(truncated); uint64_t fractional = bits & mask; if (fractional >= (1ULL << (shift - 1))) { result += 1.0; } return result; } 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 uint32_t FLOATL_MANT_DIG__; // FLOATL_MANT_BITS__ + 1 int32_t FLOATL_MIN_EXP__; // - FLOATL_EXP_MID_VALUE__ + 2 uint32_t FLOATL_MAX_EXP__; // FLOATL_EXP_MID_VALUE__ + 1 uint32_t FLOATL_DIG__; // floor(log10(2) * FLOATL_MANT_DIG__) uint32_t FLOATL_DECIMAL_DIG__; // ceil(log10(2) * FLOATL_MANT_DIG__) + 1 int32_t FLOATL_MIN_10_EXP__; // ceil(log10(2) * (1 - FLOATL_EXP_MID_VALUE__)) uint32_t FLOATL_MAX_10_EXP__; // - FLOATL_MIN_10_EXP__ + 1 } 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"); } int floatl_cfg_info_init(FLINFO *info, unsigned int bits) { if ((bits & (bits - 1)) != 0) return 0; info->FLOATL_BIT_PARTS__ = bits; 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); info->FLOATL_MANT_DIG__ = info->FLOATL_MANT_BITS__ + 1; info->FLOATL_MIN_EXP__ = - info->FLOATL_EXP_MID_VALUE__ + 2; info->FLOATL_MAX_EXP__ = info->FLOATL_EXP_MID_VALUE__ + 1; info->FLOATL_DIG__ = floor(log10(2) * info->FLOATL_MANT_DIG__); info->FLOATL_DECIMAL_DIG__ = ceil(log10(2) * info->FLOATL_MANT_DIG__) + 1; info->FLOATL_MIN_10_EXP__ = ceil(log10(2) * (int32_t)(1 - info->FLOATL_EXP_MID_VALUE__)); info->FLOATL_MAX_10_EXP__ = - info->FLOATL_MIN_10_EXP__ + 1; memset(info->buffer, 0, info->FLOATL_U32_PARTS__ * sizeof(uint32_t)); return 1; } 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_const_pi(FLINFO *info) { memset(info->buffer, 0, info->FLOATL_U32_PARTS__ * sizeof(uint32_t)); floatl_cfg_set_exp(info, 1); floatl_cfg_set_mant(info, FLOATL_CFG_MANT_PI); return info; } FLINFO *floatl_cfg_const_e(FLINFO *info) { memset(info->buffer, 0, info->FLOATL_U32_PARTS__ * sizeof(uint32_t)); floatl_cfg_set_exp(info, 1); floatl_cfg_set_mant(info, FLOATL_CFG_MANT_E); 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; } FLINFO *floatl_cfg_min(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_max(FLINFO *info) { memset(info->buffer, -1, info->FLOATL_U32_PARTS__ * sizeof(uint32_t)); floatl_cfg_set_sign(info, 0); floatl_cfg_set_exp_real(info, 0xFFFFFFFE); return info; } FLINFO *floatl_cfg_epsilon(FLINFO *info) { memset(info->buffer, 0, info->FLOATL_U32_PARTS__ * sizeof(uint32_t)); info->buffer[0] |= 1; 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; } /* Enable PI and E mant configurations */ if (!FLOATL_CFG_MANT_PI || !FLOATL_CFG_MANT_E) { fprintf(stdout, "[ERROR] Enable `FLOATL_CFG_MANT_PI` and `FLOATL_CFG_MANT_E` in `floatl_cfg.h` file"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; floatl_cfg_info_init(&info, tb); 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_MANT_DIG__ %u"NEWLINE, info.FLOATL_MANT_DIG__ ); fprintf(output, "#define __FLOATL_MIN_EXP__ %d"NEWLINE, info.FLOATL_MIN_EXP__ ); fprintf(output, "#define __FLOATL_MAX_EXP__ %u"NEWLINE, info.FLOATL_MAX_EXP__ ); fprintf(output, "#define __FLOATL_DIG__ %u"NEWLINE, info.FLOATL_DIG__ ); fprintf(output, "#define __FLOATL_DECIMAL_DIG__ %u"NEWLINE, info.FLOATL_DECIMAL_DIG__ ); fprintf(output, "#define __FLOATL_MIN_10_EXP__ %d"NEWLINE, info.FLOATL_MIN_10_EXP__ ); fprintf(output, "#define __FLOATL_MAX_10_EXP__ %u"NEWLINE, info.FLOATL_MAX_10_EXP__ ); 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_CONST_PI__ "); floatl_cfg_const_out(output, floatl_cfg_const_pi(&info) ); fprintf(output, "#define __FLOATL_CONST_E__ "); floatl_cfg_const_out(output, floatl_cfg_const_e(&info) ); 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, "#define __FLOATL_MIN__ "); floatl_cfg_const_out(output, floatl_cfg_min(&info) ); fprintf(output, "#define __FLOATL_MAX__ "); floatl_cfg_const_out(output, floatl_cfg_max(&info) ); fprintf(output, "#define __FLOATL_EPSILON__ "); floatl_cfg_const_out(output, floatl_cfg_epsilon(&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"); } } /*----------------------------------------------------------------------------------*/ /* 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? // // 1234567890 // floatl a = floatl_from("0x1.26580B48p+30"); // 1 001001100101100000001011010010 00 // floatl a = FLOATL_CONST_0; // FLINFO info; // floatl_cfg_info_init(&info, sizeof(floatl) * 8); // 1234567890 // 1 001001100101100000001011010010 00 // floatl_cfg_set_exp(&info, 30); // floatl_cfg_set_mant(&info, "001001100101100000001011010010"); // 123456789012345678901234567890 // 1 100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010 // floatl_cfg_set_exp(&info, 96); // floatl_cfg_set_mant(&info, "100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010"); // a = *((floatl *)(info.buffer)); // 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("12345678901234567890.123456789"); floatl b = floatl_from("98765432109876543210.987654321"); printf("a %s\r\n", floatl_show(a, buffer, sizeof(buffer), "%f")); printf("b %s\r\n", floatl_show(b, buffer, sizeof(buffer), "%f")); printf("a + b: %s\r\n", floatl_show(floatl_add(a, b), buffer, sizeof(buffer), "%f")); printf("a - b: %s\r\n", floatl_show(floatl_sub(a, b), buffer, sizeof(buffer), "%f")); printf("a * b: %s\r\n", floatl_show(floatl_mul(a, b), buffer, sizeof(buffer), "%f")); printf("a / b: %s\r\n", floatl_show(floatl_div(a, b), buffer, sizeof(buffer), "%f")); printf("-a: %s\r\n", floatl_show(floatl_neg(a), buffer, sizeof(buffer), "%f")); printf("|a|: %s\r\n", floatl_show(floatl_abs(a), buffer, sizeof(buffer), "%f")); printf("a > b: %d\r\n", floatl_gt(a, b)); printf("a >= b: %d\r\n", floatl_ge(a, b)); printf("a < b: %d\r\n", floatl_lt(a, b)); printf("a <= b: %d\r\n", floatl_le(a, b)); printf("a == b: %d\r\n", floatl_eq(a, b)); printf("a != b: %d\r\n", floatl_ne(a, b)); } 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 double v = -3.14; printf("ceil %f\r\n", ceil(v)); printf("floor %f\r\n", floor(v)); printf("round %f\r\n", round(v)); printf("double_ceil %f\r\n", double_ceil(v)); printf("double_floor %f\r\n", double_floor(v)); printf("double_round %f\r\n", double_round(v)); printf("floatl_ceil %s\r\n", floatl_show(floatl_ceil(floatl(v)), buffer, sizeof(buffer), "%f")); printf("floatl_floor %s\r\n", floatl_show(floatl_floor(floatl(v)), buffer, sizeof(buffer), "%f")); printf("floatl_round %s\r\n", floatl_show(floatl_round(floatl(v)), buffer, sizeof(buffer), "%f")); printf("to_d %f\r\n", floatl_to_d(FLOATL_PI)); } /************************************************************************************/ /************************************* 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