mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
160 lines
3.9 KiB
C
160 lines
3.9 KiB
C
/*
|
|
* Copyright (C) 2018 Eistec AB
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "embUnit.h"
|
|
#include "tests-frac.h"
|
|
|
|
#include "kernel_defines.h"
|
|
#include "frac.h"
|
|
#include "div.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
static const uint32_t u32_fraction_operands[] = {
|
|
1ul,
|
|
2ul,
|
|
5ul,
|
|
10ul,
|
|
100ul,
|
|
1000ul,
|
|
1000000ul,
|
|
2000000ul,
|
|
4000000ul,
|
|
8000000ul,
|
|
16000000ul,
|
|
32000000ul,
|
|
641ul,
|
|
274177ul,
|
|
32768ul,
|
|
9600ul,
|
|
38400ul,
|
|
115200ul,
|
|
230400ul,
|
|
460800ul,
|
|
921600ul,
|
|
4096ul,
|
|
15625ul,
|
|
125ul,
|
|
1048576ul,
|
|
0x10000000ul,
|
|
0x1000000ul,
|
|
1000000000ul,
|
|
999999733ul, /* <- prime */
|
|
512000000ul,
|
|
1024000000ul,
|
|
0x40000000ul,
|
|
0x80000000ul,
|
|
0xc0000000ul,
|
|
0xe0000000ul,
|
|
0xf0000000ul,
|
|
0xfffffff0ul,
|
|
0xfffffff8ul,
|
|
0xfffffffcul,
|
|
0xfffffffeul,
|
|
0xfffffffful,
|
|
};
|
|
|
|
static const uint32_t u32_test_values[] = {
|
|
0ul,
|
|
1ul,
|
|
10ul,
|
|
32ul,
|
|
15625ul,
|
|
15625ul*5,
|
|
(15625ul*5)+1,
|
|
0xfffful,
|
|
0xfffful<<10,
|
|
1234567890ul,
|
|
99999999ul,
|
|
1000000ul,
|
|
115200ul,
|
|
38400ul,
|
|
57600ul,
|
|
921600ul,
|
|
32768ul,
|
|
16000000ul,
|
|
15999999ul,
|
|
32767ul,
|
|
327679999ul,
|
|
100000000ul,
|
|
2100012683ul, /* <- prime */
|
|
0x7ffffffful,
|
|
0x80000000ul,
|
|
0xc0000000ul,
|
|
0xe0000000ul,
|
|
0xf0000000ul,
|
|
0xfffffff0ul,
|
|
0xfffffff8ul,
|
|
0xfffffffcul,
|
|
0xfffffffeul,
|
|
0xfffffffful,
|
|
};
|
|
|
|
#define N_U32_OPERANDS ARRAY_SIZE(u32_fraction_operands)
|
|
#define N_U32_VALS ARRAY_SIZE(u32_test_values)
|
|
|
|
static void test_frac_scale32(void)
|
|
{
|
|
for (unsigned k = 0; k < N_U32_OPERANDS; ++k) {
|
|
for (unsigned j = 0; j < N_U32_OPERANDS; ++j) {
|
|
uint32_t num = u32_fraction_operands[j];
|
|
uint32_t den = u32_fraction_operands[k];
|
|
frac_t frac;
|
|
frac_init(&frac, num, den);
|
|
for (unsigned i = 0; i < N_U32_VALS; i++) {
|
|
DEBUG("Scaling %" PRIu32 " by (%" PRIu32 " / %" PRIu32 "), ",
|
|
u32_test_values[i], num, den);
|
|
/* intermediate result */
|
|
volatile uint64_t tmp = (uint64_t)u32_test_values[i] * num;
|
|
volatile uint64_t expected = tmp / (uint64_t)den;
|
|
if (expected > 0xfffffffful) {
|
|
expected &= 0xfffffffful;
|
|
}
|
|
uint32_t actual = frac_scale(&frac, u32_test_values[i]);
|
|
if ((uint32_t)expected != actual) {
|
|
int32_t diff = actual - expected;
|
|
DEBUG("%" PRIu32 " * (%" PRIu32 " / %" PRIu32 ")"
|
|
" tmp %" PRIu64 " expect %" PRIu32 ", actual %" PRIu32
|
|
", diff = %" PRId32 " shift=%u\n",
|
|
u32_test_values[i], num, den, tmp, (uint32_t)expected,
|
|
actual, diff, frac.shift);
|
|
|
|
/* The frac algorithm sacrifices accuracy for speed,
|
|
* some large numbers will be incorrectly rounded,
|
|
* resulting in small differences here.. */
|
|
uint32_t max_error = frac_scale(&frac, 2);
|
|
max_error = max_error ? max_error : 1;
|
|
TEST_ASSERT_EQUAL_INT(1, diff >= 0);
|
|
if ((uint32_t)diff <= max_error) {
|
|
continue;
|
|
}
|
|
}
|
|
TEST_ASSERT_EQUAL_INT((uint32_t)expected, (uint32_t)actual);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Test *tests_frac_tests(void)
|
|
{
|
|
EMB_UNIT_TESTFIXTURES(fixtures) {
|
|
new_TestFixture(test_frac_scale32),
|
|
};
|
|
|
|
EMB_UNIT_TESTCALLER(frac_tests, NULL, NULL, fixtures);
|
|
|
|
return (Test *)&frac_tests;
|
|
}
|
|
|
|
void tests_frac(void)
|
|
{
|
|
TESTS_RUN(tests_frac_tests());
|
|
}
|