mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 16:56:42 +08:00
2. Add the floatl initial version 3. Add the intl_print function 4. Fix intl_from issue 5. Add intl unit test code
509 lines
17 KiB
C
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
|