varch/test/test_intl.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

509 lines
17 KiB
C

#include <stdio.h>
#include <string.h>
#if defined(TEST_TARGET_intl)
#include <varch/command.h>
#include <varch/unitt.h>
#include <varch/intl.h>
#else
#include "init.h"
#include "command.h"
#include "unitt.h"
#include "kern.h"
#include "intl.h"
#endif
static char pbuff[INTL_PRINT_MAX] = {0};
/************************************************************************************/
/************************************* Unit Test ************************************/
/************************************************************************************/
// #define EXIT_TEST
extern uint64_t unitt_clock(void);
static intl random_intl()
{
intl random = INTL_ZERO;
for (int i = 0; i < __INTL_U32_PARTS__; i++)
{
random.u32[i] = rand();
}
return random;
}
static const char* random_format()
{
const char *format[4] = { "d", "#b", "#o", "#x" };
return format[rand() % 4];
}
static int test_convert(void)
{
for (int i = 0; i < 100; i++)
{
intl src = random_intl();
intl dst = intl_from(intl_show(src, pbuff, sizeof(pbuff), random_format()));
if (!intl_eq(src, dst))
{
printf("convert fail: \r\n");
printf("src: %s\r\n", intl_show(src, pbuff, sizeof(pbuff), "x"));
printf("dst: %s\r\n", intl_show(dst, pbuff, sizeof(pbuff), "x"));
#if defined (EXIT_TEST)
exit(0);
#endif
return UNITT_E_FAIL;
}
}
return UNITT_E_OK;
}
/* Need config intl as 64bits */
static int test_accuracy(void)
{
for (int i = 0; i < 1000; i++)
{
int op = rand() % 10;
uint8_t sh = 0;
intl a = random_intl();
intl b = random_intl();
intl c = INTL_ZERO;
int64_t x = 0;
int64_t y = 0;
int64_t z = 0;
memcpy(&x, &a, sizeof(x));
memcpy(&y, &b, sizeof(y));
/* Skip the division by 0 */
if (op == 3 && y == 0) continue;
/* Adjust shift */
if (op == 8 || op == 9) { sh = y; sh %= 64; }
if (op == 0) { c = intl_add(a, b); z = x + y; }
else if (op == 1) { c = intl_sub(a, b); z = x - y; }
else if (op == 2) { c = intl_mul(a, b); z = x * y; }
else if (op == 3) { c = intl_div(a, b); z = x / y; }
else if (op == 4) { c = intl_mod(a, b); z = x % y; }
else if (op == 5) { c = intl_and(a, b); z = x & y; }
else if (op == 6) { c = intl_xor(a, b); z = x ^ y; }
else if (op == 7) { c = intl_or (a, b); z = x | y; }
else if (op == 8) { c = intl_shl(a, sh); z = x << sh; }
else if (op == 9) { c = intl_shr(a, sh); z = x >> sh; }
if (memcmp(&c, &z, sizeof(z)) != 0)
{
printf("accuracy fail: %d,%d\r\n", op, sh);
printf("c: %s\r\n", intl_show(c, pbuff, sizeof(pbuff), "d"));
printf("z: %lld\r\n", z);
#if defined (EXIT_TEST)
exit(0);
#endif
return UNITT_E_FAIL;
}
}
return UNITT_E_OK;
}
static void unitt_task(void)
{
static UNITT_TCASE rand_tests[] = {
UNITT_TCASE(test_convert),
#if defined (INTL_USE_64BITS)
UNITT_TCASE(test_accuracy),
#endif
};
static UNITT suites[] = {
{ "intl suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock },
};
UNITT_EXE(suites);
}
/************************************************************************************/
/************************************* Base Test ************************************/
/************************************************************************************/
void intl_gen_cfg(uint32_t bits, const char *filename)
{
#define MINBITS 64
#define NEWLINE "\n" // "\r\n" //
FILE* output = stdout; // Default output to standard output
if (filename != NULL)
{
output = fopen(filename, "w");
if (output == NULL)
{
fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE);
return;
}
}
/* The number of bits in an intl needs to be an exponent of two */
if ((bits & (bits - 1)) != 0)
{
fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE);
return;
}
/* Limiting the minimum bit */
if (bits < MINBITS)
{
fprintf(stdout, "[ERROR] `bits` too small\r\b");
return;
}
fprintf(output, "/*****************************************************************/"NEWLINE);
fprintf(output, "/* Config start */"NEWLINE);
fprintf(output, "/*****************************************************************/"NEWLINE);
for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1)
{
if (tb == bits)
{
fprintf(output, "#define INTL_USE_%uBITS"NEWLINE, tb);
}
else
{
fprintf(output, "// #define INTL_USE_%uBITS"NEWLINE, tb);
}
}
fprintf(output, ""NEWLINE);
intl temp;
for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1)
{
if (tb == MINBITS)
{
fprintf(output, "#if defined(INTL_USE_%uBITS)"NEWLINE, tb);
}
else
{
fprintf(output, "#elif defined(INTL_USE_%uBITS)"NEWLINE, tb);
}
uint32_t BIT_PARTS ; /* bits */
uint32_t U32_PARTS ; /* __INTL_BIT_PARTS__ / 32 */
uint32_t U16_PARTS ; /* __INTL_BIT_PARTS__ / 16 */
uint32_t MAX_BIN ; /* __INTL_BIT_PARTS__ + 1 */
uint32_t MAX_DEC ; /* strlen(intl_shl(intl(1), __INTL_BIT_PARTS__ - 1)) + 1 */
uint32_t MAX_HEX ; /* __INTL_BIT_PARTS__ / 4 + 1 */
BIT_PARTS = tb;
U32_PARTS = BIT_PARTS >> (5);
U16_PARTS = BIT_PARTS >> (4);
MAX_BIN = BIT_PARTS + 3; // "0b" + '\0'
MAX_DEC = MAX_BIN; // First apply as MAX bin maximum value, and then according to the actual calculation
MAX_HEX = (BIT_PARTS >> (2)) + 3; // "0x" + '\0'
/* The current configuration is applied */
if (sizeof(temp) == (bits >> 3))
{
char buffer[__INTL_P_MAX_BIN__];
MAX_DEC = intl_print(intl_shl(intl(1), BIT_PARTS - 1), buffer, sizeof(buffer), "d") + 1; // '\0'
}
fprintf(output, "#define __INTL_BIT_PARTS__ %u"NEWLINE, BIT_PARTS);
fprintf(output, "#define __INTL_U32_PARTS__ %u"NEWLINE, U32_PARTS);
fprintf(output, "#define __INTL_U16_PARTS__ %u"NEWLINE, U16_PARTS);
fprintf(output, "#define __INTL_P_MAX_BIN__ %u"NEWLINE, MAX_BIN);
fprintf(output, "#define __INTL_P_MAX_DEC__ %u"NEWLINE, MAX_DEC);
fprintf(output, "#define __INTL_P_MAX_HEX__ %u"NEWLINE, MAX_HEX);
/* __INTL_MAX__ */
fprintf(output, "#define __INTL_MAX__ (intl){.u32={");
for (uint32_t i = 0; i < U32_PARTS; i++)
{
fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x7FFFFFFF" : "-1");
}
fprintf(output, "}}"NEWLINE);
/* __INTL_MIN__ */
fprintf(output, "#define __INTL_MIN__ (intl){.u32={");
for (uint32_t i = 0; i < U32_PARTS; i++)
{
fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x80000000" : "0");
}
fprintf(output, "}}"NEWLINE);
/* __INTL_ZERO__ */
fprintf(output, "#define __INTL_ZERO__ (intl){.u32={");
for (uint32_t i = 0; i < U32_PARTS; i++)
{
fprintf(output, "0,");
}
fprintf(output, "}}"NEWLINE);
}
fprintf(output, "#endif"NEWLINE);
fprintf(output, "/*****************************************************************/"NEWLINE);
fprintf(output, "/* Config end */"NEWLINE);
fprintf(output, "/*****************************************************************/"NEWLINE);
fprintf(stdout, "\r\n\r\n-------------------------------------------------------------\r\n"NEWLINE);
/* The current configuration is not applied */
if (sizeof(temp) != (bits >> 3))
{
fprintf(stdout, "[TODO][%s] Apply the current configuration and run it again to get the new `__INTL_P_MAX_DEC__`"NEWLINE, filename);
}
else
{
fprintf(stdout, "[INFO][%s] The configuration has been generated, copy it to the `intl_cfg.h` range specified"NEWLINE, filename);
}
if (filename != NULL)
{
fclose(output);
}
}
static void test_define(void)
{
intl a = intl(0);
intl b = intl(10);
intl c = intl(-10);
intl d = intl(0xFF);
intl e = intl_from("0");
intl f = intl_from("100");
intl g = intl_from("-100");
intl h = intl_from("123456789123456789123456789");
intl i = intl_from("0b1110000001111100101010100");
intl j = intl_from("0o1236541236763210233642166");
intl k = intl_from("0xF125E3F6D743648EEFFF12356");
intl max = INTL_MAX;
intl min = INTL_MIN;
intl n0 = INTL_ZERO;
}
static void test_print(void)
{
intl a = intl_from("123456789123456789123456789");
printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "dx"));
printf("a: %s\r\n", intl_show(INTL_ZERO, pbuff, sizeof(pbuff), "#x"));
printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "#o"));
printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "#x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "10x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "010x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "-10x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "-010x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#10x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#010x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#-10x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#-010x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#x"));
printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#0x"));
printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "#d"));
printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "#10d"));
printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "-#d"));
}
static void test_calculate(void)
{
intl a = intl_from("123456789123456789123456789");
intl b = intl_from("987654321987654321987654321");
printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "d"));
printf("b: %s\r\n", intl_show(b, pbuff, sizeof(pbuff), "d"));
printf("a + b: %s\r\n", intl_show(intl_add(a, b), pbuff, sizeof(pbuff), "d"));
printf("a - b: %s\r\n", intl_show(intl_sub(a, b), pbuff, sizeof(pbuff), "d"));
printf("a * b: %s\r\n", intl_show(intl_mul(a, b), pbuff, sizeof(pbuff), "d"));
printf("b / a: %s\r\n", intl_show(intl_div(a, b), pbuff, sizeof(pbuff), "d"));
printf("b %% a: %s\r\n", intl_show(intl_mod(a, b), pbuff, sizeof(pbuff), "d"));
printf("a & b: %s\r\n", intl_show(intl_and(a, b), pbuff, sizeof(pbuff), "d"));
printf("a | b: %s\r\n", intl_show(intl_or(a, b), pbuff, sizeof(pbuff), "d"));
printf("a ^ b: %s\r\n", intl_show(intl_xor(a, b), pbuff, sizeof(pbuff), "d"));
printf("~a: %s\r\n", intl_show(intl_not(a), pbuff, sizeof(pbuff), "d"));
printf("a << 1: %s\r\n", intl_show(intl_shl(a, 1), pbuff, sizeof(pbuff), "d"));
printf("b >> 1: %s\r\n", intl_show(intl_shr(a, 1), pbuff, sizeof(pbuff), "d"));
printf("a++: %s\r\n", intl_show(intl_inc(a), pbuff, sizeof(pbuff), "d"));
printf("b--: %s\r\n", intl_show(intl_dec(a), pbuff, sizeof(pbuff), "d"));
printf("a > b: %d\r\n", intl_gt(a, b));
printf("a >= b: %d\r\n", intl_ge(a, b));
printf("a < b: %d\r\n", intl_lt(a, b));
printf("a <= b: %d\r\n", intl_le(a, b));
printf("a == b: %d\r\n", intl_eq(a, b));
printf("a != b: %d\r\n", intl_ne(a, b));
}
static void test_base(void)
{
// test_define();
// test_print();
test_calculate();
}
/************************************************************************************/
/************************************* Command ************************************/
/************************************************************************************/
static void usage(void)
{
printf(
"Usage: intl [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 intl configuration file code segment, need specify -f -b\n"
" <print> Print an intl number\n"
" -l <format> Format string, 10d, 08x, ...\n"
" -o <op function> Operate function, add, sub, mul, div, ...\n"
" -n <intl> intl 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;
intl n[2] = {INTL_ZERO, INTL_ZERO};
int in = 0;
char *op = NULL;
char *format = NULL;
/* reset getopt */
command_opt_init();
while (1)
{
int opt = command_getopt(argc, argv, "e:hvu::f:b:n:o:l:");
if (opt == -1) break;
switch (opt)
{
case 'l' :
format = command_optarg;
break;
case 'o' :
op = command_optarg;
break;
case 'n' :
if (in < 2) n[in++] = intl_from(command_optarg);
break;
case 'b' :
bits = atoi(command_optarg);
break;
case 'f' :
filename = command_optarg;
break;
case 'u' :
if (command_optarg) ut_period = atoi(command_optarg);
break;
case 'e' :
execute = command_optarg;
break;
case 'v' :
printf("intl version %d.%d.%d\r\n", INTL_V_MAJOR, INTL_V_MINOR, INTL_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((unsigned int)time(NULL));
#if defined(TEST_TARGET_intl)
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"))
{
intl_gen_cfg(bits, filename);
}
else if (!strcmp(execute, "cal"))
{
intl result = INTL_ZERO;
if (!strcmp(op, "add")) result = intl_add(n[0], n[1]);
else if (!strcmp(op, "sub")) result = intl_sub(n[0], n[1]);
else if (!strcmp(op, "mul")) result = intl_mul(n[0], n[1]);
else if (!strcmp(op, "div")) result = intl_div(n[0], n[1]);
else if (!strcmp(op, "mod")) result = intl_mod(n[0], n[1]);
else if (!strcmp(op, "and")) result = intl_and(n[0], n[1]);
else if (!strcmp(op, "xor")) result = intl_xor(n[0], n[1]);
else if (!strcmp(op, "or")) result = intl_or(n[0], n[1]);
else if (!strcmp(op, "shl")) result = intl_shl(n[0], *(uint32_t *)(&n[1]));
else if (!strcmp(op, "shr")) result = intl_shr(n[0], *(uint32_t *)(&n[1]));
else printf("No such function!\r\n");
printf("result: %s\r\n", intl_show(result, pbuff, sizeof(pbuff), "d"));
}
else if (!strcmp(execute, "print"))
{
printf("%s\r\n", intl_show(n[0], pbuff, sizeof(pbuff), format));
}
}
else
{
test_base();
}
return 0;
}
/************************************************************************************/
/************************************ Test entry ************************************/
/************************************************************************************/
#if defined(TEST_TARGET_intl)
int main(int argc, char *argv[])
{
return test(argc, argv);
}
#else
void test_intl(void)
{
command_export("intl", test);
}
init_export_app(test_intl);
#endif