varch/test/test_floatl.c
Lamdonn f2b0a31bb3 1. Fix test_floatl.c compile fail issue
2. Update muti-core compile run.sh
2025-11-19 22:31:52 +08:00

1758 lines
53 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>
#include <stdint.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_;
}
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(&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
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 <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