Skip to content

Commit

Permalink
Fixed point test cases (#17)
Browse files Browse the repository at this point in the history
* 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 <mysterymath@gmail.com>
  • Loading branch information
jroweboy and mysterymath authored Mar 22, 2024
1 parent 1cc4150 commit 1bcdd8d
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 0 deletions.
1 change: 1 addition & 0 deletions SingleSource/UnitTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
198 changes: 198 additions & 0 deletions SingleSource/UnitTests/fixed_point.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include <fixed_point.h>
#include <float.h>
#include <stdio.h>

// My extremely hardcoded print float method since there isn't %f print support
template <typename T> 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 <bool Signed = true, typename T>
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;
}
56 changes: 56 additions & 0 deletions SingleSource/UnitTests/fixed_point.reference_output
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 1bcdd8d

Please sign in to comment.