From 1bcdd8d39280edefa9a0093cba2f6e666e9ec701 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Fri, 22 Mar 2024 16:56:38 -0400 Subject: [PATCH] Fixed point test cases (#17) * In progress test suite for fixed point numbers * Fix print float and add some more tests * Clang format * Fix tests --------- Co-authored-by: Daniel Thornburgh --- SingleSource/UnitTests/CMakeLists.txt | 1 + SingleSource/UnitTests/fixed_point.cpp | 198 ++++++++++++++++++ .../UnitTests/fixed_point.reference_output | 56 +++++ 3 files changed, 255 insertions(+) create mode 100644 SingleSource/UnitTests/fixed_point.cpp create mode 100644 SingleSource/UnitTests/fixed_point.reference_output diff --git a/SingleSource/UnitTests/CMakeLists.txt b/SingleSource/UnitTests/CMakeLists.txt index ffe832efe..c443f4af2 100644 --- a/SingleSource/UnitTests/CMakeLists.txt +++ b/SingleSource/UnitTests/CMakeLists.txt @@ -126,6 +126,7 @@ if(ARCH STREQUAL "MOS") target_link_libraries(StructModifyTest PRIVATE printf_flt) target_link_libraries(byval-alignment PRIVATE printf_flt) target_link_libraries(printf_float PRIVATE printf_flt) + target_link_libraries(fixed_point PRIVATE printf_flt) else() if (COMPILER_HAS_MATRIX_FLAG) set_property(TARGET matrix-types-spec PROPERTY LINK_OPTIONS -fenable-matrix) diff --git a/SingleSource/UnitTests/fixed_point.cpp b/SingleSource/UnitTests/fixed_point.cpp new file mode 100644 index 000000000..35cc45d45 --- /dev/null +++ b/SingleSource/UnitTests/fixed_point.cpp @@ -0,0 +1,198 @@ +#include +#include +#include + +// My extremely hardcoded print float method since there isn't %f print support +template void print_float(const char *name, T fp) { + uint8_t fsize = fp.frac_bitcount(); + float fscale = (float)(1llu << fsize); + auto f = fp.get(); + if ((fp.int_bitcount() + fsize) == 24 && !fp.is_signed()) { + // If we are writing a 24bit number, the underlying type is 32 bit, so mask + // off the upper byte + f &= 0xffffff; + } + float val = f / fscale; + printf("%s %.02f\n", name, val); +} + +template +void print_hex(const char *name, T fp) { + switch (sizeof(fp)) { + case 1: + if (Signed) { + printf("%s %lX\n", name, (int8_t)fp.get()); + } else { + printf("%s %lX\n", name, (uint8_t)fp.get()); + } + break; + case 2: + if (Signed) { + printf("%s %X\n", name, (int16_t)fp.get()); + } else { + printf("%s %X\n", name, (uint16_t)fp.get()); + } + break; + case 3: + case 4: + if (Signed) { + printf("%s %lX\n", name, (int32_t)fp.get()); + } else { + printf("%s %lX\n", name, (uint32_t)fp.get()); + } + break; + default: + break; + } +} + +int main(void) { + //////// + // Constructor tests + + // basic literal constructor + using namespace fixedpoint_literals; + f8_8 basic_constructor{100}; + printf("basic_constructor %d.%d\n", (char)basic_constructor.as_i(), + (char)basic_constructor.as_f()); + + // using a negative value in a signed class + f8_8 signed_value{-100}; + print_float("signed_value", signed_value); + + // using an signed value with a negative number and storing to an unsigned is + // converted to the unsigned value + fu8_8 unsigned_value{-100}; + printf("unsigned_value %hd.%hd\n", (uint16_t)unsigned_value.get() / 256, + (uint8_t)((((int16_t)unsigned_value.as_f()) * 256) / 100)); + + // floating point number constructor + f8_8 from_float{10.9}; + print_float("from_float", + from_float); // gets rounded a bit when printing so it says 10.89 + + // copy constructors + // basic copy constructor with same sizes + f8_8 copy_same_size = from_float; + print_float("copy_same_size", copy_same_size); + + // copy constructor from signed to unsigned type + fu8_8 copy_of_signed_positive = basic_constructor; + print_float("copy_of_signed_positive", copy_of_signed_positive); + // copy constructor from negative signed number to unsigned treats the integer + // portion as unsigned + fu8_8 copy_of_signed_negative = signed_value; + print_float("copy_of_signed_negative", copy_of_signed_negative); + // copy constructor with a larger int size (same float size) + f16_8 copy_bigger_size = basic_constructor; + print_float("copy_bigger_size", copy_bigger_size); + + // copy constructor with a signed larger int size sign extends + f16_8 copy_bigger_signed = signed_value; + print_float("copy_bigger_signed", copy_bigger_signed); + print_hex("copy_bigger_signed", + copy_bigger_signed); // verify that it gets sign extended + + // Copy constructor to an unsigned larger int with a signed number + fu16_8 copy_bigger_unsigned = signed_value; + print_float("copy_bigger_unsigned", copy_bigger_unsigned); + print_hex("copy_bigger_unsigned", copy_bigger_unsigned); + + // Copy constructor with a smaller int size with a signed number truncates the + // upper bits + f16_8 bigger_int_size = -800.8_16_8; // + f8_8 smaller_int_size = bigger_int_size.as<8, 8>(); + print_float("smaller_int_size", smaller_int_size); // truncates to df + + // Copy constructor with a different float size resizes the float value + fu8_8 float_half_value = 12.5_u8_8; + fu12_12 bigger_float_size = float_half_value.as<12, 12>(); + print_float("bigger_float_size", bigger_float_size); + + fu16_16 big_float_size = 18.7_u16_16; + fu8_8 small_float_size = big_float_size.as<8, 8, false>(); + print_float("small_float_size", small_float_size); + + //////////////// + // Operator overloads + + f8_8 unary_minus_op = 100.6_8_8; + unary_minus_op = -unary_minus_op; + print_float("unary_minus_op", unary_minus_op); + print_hex("unary_minus_op", unary_minus_op); + + f8_8 unary_negate_op = ~100.6_8_8; + print_float("unary_negate_op", unary_negate_op); + + // 127.5 % 100.4 == 27.1 + f8_8 modulo_op = 127.5_8_8; + print_float("modulo_op", modulo_op % 100.4_8_8); + + // 127.5 & 124.0 == 124.0 + f8_8 binary_and = 127.5_8_8; + print_float("binary_and", binary_and & 124.0_8_8); + + // 2.5 | 8.0 == 10.5 + f8_8 binary_or = 2.5_8_8; + print_float("binary_or", binary_or | 8.0_8_8); + + // 3.5 ^ 5.3 == 0x380 ^ 0x54c == 0x6cc (6.8) + f8_8 binary_xor = 3.5_8_8; + print_float("binary_xor", binary_xor ^ 5.3_8_8); + + //////////////// + // Arithmetic operators + + f8_8 small_signed = -50.8_8_8; + f16_8 large_signed = -400.3_16_8; + fu8_8 small_unsigned = 200.1_u8_8; + fu16_8 large_unsigned = 1000.6_u16_8; + + print_float("add int small signed", small_signed + 1); + print_float("add fp small signed", small_signed + 1.1_8_8); + print_float("add int small unsigned", small_unsigned + 1); + print_float("add fp small unsigned", small_unsigned + 1.1_u8_8); + // Overflow wraps around and doesn't extend the int type + print_float("add fp small signed overflow", small_signed + -100.1_8_8); + print_float("add fp small unsigned overflow", small_unsigned + 100.1_u8_8); + // Adding large type + small type returns large type + print_float("add fp large + small signed", large_signed + small_signed); + print_float("add fp large + small unsigned", large_unsigned + small_unsigned); + // Adding small type + large type promotes to the larger type + print_float("add fp small + large signed", small_signed + large_signed); + print_float("add fp small + large unsigned", small_unsigned + large_unsigned); + + print_float("sub int small signed", small_signed - 1); + print_float("sub fp small signed", small_signed - 1.1_8_8); + print_float("sub int small unsigned", small_unsigned - 1); + print_float("sub fp small unsigned", small_unsigned - 1.1_u8_8); + print_float("sub fp small signed overflow", small_signed - -100.1_8_8); + print_float("sub fp small unsigned overflow", small_unsigned - 100.1_u8_8); + print_float("sub fp large - small signed", large_signed - small_signed); + print_float("sub fp large - small unsigned", large_unsigned - small_unsigned); + print_float("sub fp small - large signed", small_signed - large_signed); + auto out = small_unsigned - large_unsigned; + print_float("sub fp small - large unsigned", out); + print_hex("sub fp small - large unsigned", out); + + // Multiplication checks + auto signval = -10.8_8_8; + auto unsignval = 10.8_8_8; + print_float("mul int small signed", signval * 3); + print_float("mul fp small signed", signval * 3.3_8_8); + print_float("mul int overflow signed", small_signed * 3); + print_float("mul fp overflow signed", small_signed * 3.3_8_8); + print_float("mul int small signed", unsignval * 3); + print_float("mul fp small signed", unsignval * 3.3_8_8); + print_float("mul int overflow signed", small_unsigned * 3); + print_float("mul fp overflow signed", small_unsigned * 3.3_8_8); + + // Comparison checks + printf("sign < unsigned %s\n", (-10.0_8_8 < 10.0_8_8) ? "true" : "false"); + printf("sign > unsigned %s\n", (-10.0_8_8 > 10.0_8_8) ? "true" : "false"); + printf("sign == unsigned %s\n", (-10.0_8_8 == 10.0_8_8) ? "true" : "false"); + printf("large sign < unsigned %s\n", + (-1000.0_16_8 < 10.0_8_8) ? "true" : "false"); + + return 0; +} diff --git a/SingleSource/UnitTests/fixed_point.reference_output b/SingleSource/UnitTests/fixed_point.reference_output new file mode 100644 index 000000000..20b9aedaf --- /dev/null +++ b/SingleSource/UnitTests/fixed_point.reference_output @@ -0,0 +1,56 @@ +basic_constructor 100.0 +signed_value -100.00 +unsigned_value 156.0 +from_float 10.90 +copy_same_size 10.90 +copy_of_signed_positive 100.00 +copy_of_signed_negative 156.00 +copy_bigger_size 100.00 +copy_bigger_signed -100.00 +copy_bigger_signed FFFF9C00 +copy_bigger_unsigned 65436.00 +copy_bigger_unsigned FF9C00 +smaller_int_size -32.80 +bigger_float_size 12.50 +small_float_size 18.70 +unary_minus_op -100.60 +unary_minus_op 9B67 +unary_negate_op -100.60 +modulo_op 27.10 +binary_and 124.00 +binary_or 10.50 +binary_xor 6.80 +add int small signed -49.80 +add fp small signed -49.70 +add int small unsigned 201.10 +add fp small unsigned 201.20 +add fp small signed overflow 105.10 +add fp small unsigned overflow 44.20 +add fp large + small signed -451.09 +add fp large + small unsigned 1200.70 +add fp small + large signed -451.09 +add fp small + large unsigned 1200.70 +sub int small signed -51.80 +sub fp small signed -51.89 +sub int small unsigned 199.10 +sub fp small unsigned 199.00 +sub fp small signed overflow 49.30 +sub fp small unsigned overflow 100.00 +sub fp large - small signed -349.50 +sub fp large - small unsigned 800.50 +sub fp small - large signed 349.50 +sub fp small - large unsigned 64735.50 +sub fp small - large unsigned FFFCDF80 +mul int small signed -32.39 +mul fp small signed -35.60 +mul int overflow signed 103.61 +mul fp overflow signed 88.53 +mul int small signed 32.39 +mul fp small signed 35.59 +mul int overflow signed 88.29 +mul fp overflow signed 147.70 +sign < unsigned true +sign > unsigned false +sign == unsigned false +large sign < unsigned true +exit 0