From 0ffbcd726d6be5c32e841046869dda08b461684c Mon Sep 17 00:00:00 2001 From: schodet Date: Sun, 9 Oct 2005 16:59:46 +0000 Subject: Ajout des tests. Ajout de la doc. Correction de la version hôte de div. --- n/avr/modules/math/fixed/fixed.h | 4 +- n/avr/modules/math/fixed/fixed.txt | 50 ++++++++++++++ n/avr/modules/math/fixed/test/Makefile | 17 ++++- n/avr/modules/math/fixed/test/test_fixed.c | 105 ++++++++++++++++++++++++++--- 4 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 n/avr/modules/math/fixed/fixed.txt (limited to 'n/avr/modules/math') diff --git a/n/avr/modules/math/fixed/fixed.h b/n/avr/modules/math/fixed/fixed.h index 2337b1c..4f9f77f 100644 --- a/n/avr/modules/math/fixed/fixed.h +++ b/n/avr/modules/math/fixed/fixed.h @@ -54,11 +54,11 @@ fixed_div_f824 (int32_t a, int32_t b); #else /* HOST */ /** Multiply f8.24 by f8.24, return f8.24. */ -#define fixed_mul_f824(a, b) (((uint64_t) (a) * (uint64_t) (b) \ +#define fixed_mul_f824(a, b) (((int64_t) (a) * (int64_t) (b) \ + 0x800000LL) >> 24) /** Divide f8.24 by f8.24, return f8.24. */ -#define fixed_div_f824(a, b) (((uint64_t) (a) << 24) / (uint64_t) (b)) +#define fixed_div_f824(a, b) (((int64_t) (a) << 24) / (int64_t) (b)) #endif diff --git a/n/avr/modules/math/fixed/fixed.txt b/n/avr/modules/math/fixed/fixed.txt new file mode 100644 index 0000000..4c0ddc3 --- /dev/null +++ b/n/avr/modules/math/fixed/fixed.txt @@ -0,0 +1,50 @@ +*Title: Module AVR math à virgule fixe +*Author: Ni + +* La virgule fixe + +Le format à virgule fixe, à opposer à la virgule flottante, divise un mot +binaire en deux parties, la partie entière et la partie fractionnaire. + +L'inconvénient par rapport à la virgule flottante, c'est de pouvoir +représenter une plage plus petite de nombres. Il faut aussi faire très +attention de ne pas déborder lors des calculs intermédiaires. + +L'avantage, c'est la vitesse d'exécution, ça tombe bien, on est pressé ! + +Je vous laisse consulter internet pour plus d'informations. + +* Notation des nombres + +Pour décoder le nom des fonctions : + + [u]{i|f}x[.y] + + [u] non signé ; + [i] entier ; + [f] virgule fixe ; + [x] taille de la partie entière en bits ; + [y] taille de la partie fractionnaire en bits. + +Par exemple : + + [i16] mot signé 16 bits ; + [uf24.8] nombre en virgule fixe non signé, avec 24 bits pour la partie + entière et 8 bits pour la partie fractionnaire. + +* Format des angles + +Les angles utilisés sont dans l'intervalle [0 ; 1[. La valeur 1 correspond à 2 +pi radians, soit un tour complet. Le sens des angles orientés est le sens +trigonométrique bien sur. + +* Routines de tests + +Pour tester les algorithmes, on compile test_fixed pour hôte et pour AVR. On +lance les deux et l'on compare les résultats, ils doivent être identiques. + +La version hôte vérifie les calculs avec la bibliothèque mathématique du C. + +* Doc + +*File: uart.exd diff --git a/n/avr/modules/math/fixed/test/Makefile b/n/avr/modules/math/fixed/test/Makefile index 38517e5..c690212 100644 --- a/n/avr/modules/math/fixed/test/Makefile +++ b/n/avr/modules/math/fixed/test/Makefile @@ -12,6 +12,21 @@ AVR_MCU = atmega128 OPTIMIZE = -O2 DEFS = -LIBS = +HOST_LIBS = -lm include $(BASE)/make/Makefile.gen + +EXTRA_CLEAN_FILES += test_fixed.mul test_fixed.div test_fixed.cos \ + test_fixed.sqrt + +test_fixed.mul: test_fixed.host + echo '!m' | ./$< > $@ + +test_fixed.div: test_fixed.host + echo '!d' | ./$< > $@ + +test_fixed.cos: test_fixed.host + echo '!c' | ./$< > $@ + +test_fixed.sqrt: test_fixed.host + echo '!s' | ./$< > $@ diff --git a/n/avr/modules/math/fixed/test/test_fixed.c b/n/avr/modules/math/fixed/test/test_fixed.c index 35ea573..ff826d4 100644 --- a/n/avr/modules/math/fixed/test/test_fixed.c +++ b/n/avr/modules/math/fixed/test/test_fixed.c @@ -30,6 +30,72 @@ #include "modules/utils/utils.h" #include "io.h" +#ifdef HOST + +#include +#include +#include + +static void +check_mul (int32_t a, int32_t b, int32_t r) +{ + feclearexcept (FE_ALL_EXCEPT); + double af = (double) a / (1 << 24); + double bf = (double) b / (1 << 24); + int32_t ri = rint (af * bf * (1 << 24)); + if (r != ri && !fetestexcept (FE_INVALID)) + printf ("error: %08x * %08x != %08x (%08x)\n", a, b, r, ri); +} + +static void +check_div (int32_t a, int32_t b, int32_t r) +{ + feclearexcept (FE_ALL_EXCEPT); + double af = (double) a / (1 << 24); + double bf = (double) b / (1 << 24); + int32_t ri = af / bf * (1 << 24); + if (r != ri && !fetestexcept (FE_INVALID)) + printf ("error: %08x / %08x != %08x (%08x)\n", a, b, r, ri); +} + +static void +check_cos (int32_t a, int32_t rc, int32_t rs) +{ + double af = (double) a / (1 << 24) * 2 * M_PI; + int32_t rci = cos (af) * (1 << 24); + if (rc != rci) + printf ("error: cos (%08x) != %08x (%08x%+d)\n", + a, rc, rci, rc - rci); + int32_t rsi = sin (af) * (1 << 24); + if (rs != rsi) + printf ("error: sin (%08x) != %08x (%08x%+d)\n", + a, rs, rsi, rs - rsi); +} + +static void +check_sqrt (uint32_t a, uint32_t rf, uint16_t ri) +{ + double aff = (double) a / (1 << 8); + uint32_t rfi = sqrt (aff) * (1 << 8); + if (rf != rfi) + printf ("error: sqrt_f (%08x) != %08x (%08x%+d)\n", + a, rf, rfi, rf - rfi); + double aif = (double) a; + uint16_t rii = sqrt (aif); + if (ri != rii) + printf ("error: sqrt_i (%08x) != %04x (%04x%+d)\n", + a, ri, rii, ri - rii); +} + +#else + +# define check_mul(a, b, r) +# define check_div(a, b, r) +# define check_cos(a, rc, rs) +# define check_sqrt(a, rf, ri) + +#endif + void proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) { @@ -54,9 +120,13 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) bl = patl[bp] >> bs; proto_send2d ('a', al, bl); rl[0] = fixed_mul_f824 (al, bl); + check_mul (al, bl, rl[0]); rl[1] = fixed_mul_f824 (-al, bl); + check_mul (-al, bl, rl[1]); rl[2] = fixed_mul_f824 (al, -bl); + check_mul (al, -bl, rl[2]); rl[3] = fixed_mul_f824 (-al, -bl); + check_mul (-al, -bl, rl[3]); proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]); } for (i = 0; i < 64000; i++) @@ -65,9 +135,13 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) bl = random_u32 (); proto_send2d ('a', al, bl); rl[0] = fixed_mul_f824 (al, bl); + check_mul (al, bl, rl[0]); rl[1] = fixed_mul_f824 (-al, bl); + check_mul (-al, bl, rl[1]); rl[2] = fixed_mul_f824 (al, -bl); + check_mul (al, -bl, rl[2]); rl[3] = fixed_mul_f824 (-al, -bl); + check_mul (-al, -bl, rl[3]); proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]); } break; @@ -75,35 +149,47 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) for (ap = 0; ap < patn; ap++) for (bp = 0; bp < patn; bp++) for (as = 0; as < 32; as++) - for (bs = 0; bs < 32; bs++) + for (bs = 0; bs < 31; bs++) { al = patl[ap] >> as; bl = patl[bp] >> bs; proto_send2d ('a', al, bl); rl[0] = fixed_div_f824 (al, bl); + check_div (al, bl, rl[0]); rl[1] = fixed_div_f824 (-al, bl); + check_div (-al, bl, rl[1]); rl[2] = fixed_div_f824 (al, -bl); + check_div (al, -bl, rl[2]); rl[3] = fixed_div_f824 (-al, -bl); + check_div (-al, -bl, rl[3]); proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]); } for (i = 0; i < 64000; i++) { al = random_u32 (); bl = random_u32 (); - proto_send2d ('a', al, bl); - rl[0] = fixed_div_f824 (al, bl); - rl[1] = fixed_div_f824 (-al, bl); - rl[2] = fixed_div_f824 (al, -bl); - rl[3] = fixed_div_f824 (-al, -bl); - proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]); + if (bl != 0) + { + proto_send2d ('a', al, bl); + rl[0] = fixed_div_f824 (al, bl); + check_div (al, bl, rl[0]); + rl[1] = fixed_div_f824 (-al, bl); + check_div (-al, bl, rl[1]); + rl[2] = fixed_div_f824 (al, -bl); + check_div (al, -bl, rl[2]); + rl[3] = fixed_div_f824 (-al, -bl); + check_div (-al, -bl, rl[3]); + proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]); + } } break; case c ('c', 0): - for (al = 0; al < (1L << 24); al += 1 << 8) + for (al = 0; al < (1L << 24); al += 257) { proto_send1d ('a', al); rl[0] = fixed_cos_f824 (al); rl[1] = fixed_sin_f824 (al); + check_cos (al, rl[0], rl[1]); proto_send2d ('r', rl[0], rl[1]); } for (i = 0; i < 64000; i++) @@ -112,6 +198,7 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) proto_send1d ('a', al); rl[0] = fixed_cos_f824 (al); rl[1] = fixed_sin_f824 (al); + check_cos (al, rl[0], rl[1]); proto_send2d ('r', rl[0], rl[1]); } break; @@ -123,6 +210,7 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) proto_send1d ('a', al); rl[0] = fixed_sqrt_uf248 (al); rl[1] = fixed_sqrt_ui32 (al); + check_sqrt (al, rl[0], rl[1]); proto_send2d ('r', rl[0], rl[1]); } for (i = 0; i < 64000; i++) @@ -131,6 +219,7 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args) proto_send1d ('a', al); rl[0] = fixed_sqrt_uf248 (al); rl[1] = fixed_sqrt_ui32 (al); + check_sqrt (al, rl[0], rl[1]); proto_send2d ('r', rl[0], rl[1]); } break; -- cgit v1.2.3