blob: e783f5f5ad82008d2e8429cd618820070098dd2e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include <catch2/catch_test_macros.hpp>
#include <rapidcheck/catch.h>
#include "fixed_point.h"
TEST_CASE("fp_t addition is commutative") {
fp_t a = fp_t::from_int(1);
fp_t b = fp_t::from_int(2);
CHECK(a + b == b + a);
REQUIRE(a.raw != 0);
}
TEST_CASE("fp_t subtraction anti-commutative") {
fp_t a = fp_t::from_int(3);
fp_t b = fp_t::from_int(2);
fp_t c = fp_t::from_int(1);
fp_t d = fp_t::from_int(-1);
CHECK((a - b == c && b - a == d));
REQUIRE(a.raw != 0);
}
TEST_CASE("fp_t multiplication is commutative") {
fp_t a = fp_t::from_int(2);
fp_t b = fp_t::from_int(5);
CHECK(a * b == b * a);
REQUIRE(a.raw != 1);
}
TEST_CASE("fp_t addition overflows") {
fp_t a = fp_t::from_raw(INT32_MAX);
fp_t b = fp_t::from_raw(1);
fp_t c = fp_t::from_raw(INT32_MIN);
CHECK(a + b == c);
}
TEST_CASE("fp_t subtraction underflows") {
fp_t a = fp_t::from_raw(INT32_MIN);
fp_t b = fp_t::from_raw(1);
fp_t c = fp_t::from_raw(INT32_MAX);
CHECK(a - b == c);
}
TEST_CASE("fp_t multiplication overflows") {
fp_t a = fp_t::from_raw(INT32_MAX);
fp_t b = fp_t::from_int(2);
fp_t c = fp_t::from_raw(-2);
CHECK(a * b == c);
}
TEST_CASE("fp_t multiplication drops percision under 1 ULP") {
fp_t a = fp_t::from_raw(1);
fp_t b = fp_t::from_raw(0);
CHECK(a * a == b);
}
TEST_CASE("fp_t division is basic") {
fp_t a = fp_t::from_int(10);
fp_t b = fp_t::from_int(2);
fp_t c = fp_t::from_int(5);
CHECK(a / b == c);
}
TEST_CASE("fp_t division is sign-symmetric") {
fp_t a = fp_t::from_int(1);
fp_t b = fp_t::from_raw(-3);
fp_t neg_a = fp_t::from_raw(-a.raw);
fp_t neg_b = fp_t::from_raw(-b.raw);
CHECK(neg_a / b == a / neg_b);
}
TEST_CASE("fp_t division rounds to nearest") {
fp_t a = fp_t::from_int(1);
fp_t b = fp_t::from_int(3);
fp_t c = fp_t::from_raw(21845);
CHECK(a / b == c);
}
TEST_CASE("fp_t division handles negative operands") {
fp_t a = fp_t::from_int(-10);
fp_t b = fp_t::from_int(2);
fp_t c = fp_t::from_int(-5);
CHECK(a / b == c);
fp_t d = fp_t::from_int(10);
fp_t e = fp_t::from_int(-2);
fp_t f = fp_t::from_int(-5);
CHECK(d / e == f);
fp_t g = fp_t::from_int(-10);
fp_t h = fp_t::from_int(-2);
fp_t i = fp_t::from_int(5);
CHECK(g / h == i);
}
TEST_CASE("fp_t division truncates precision below 1 ULP") {
fp_t a = fp_t::from_raw(1);
fp_t b = fp_t::from_int(100000);
fp_t c = fp_t::from_raw(0);
CHECK(a / b == c);
}
namespace rc {
template<>
struct Arbitrary<fp_t> {
static Gen<fp_t> arbitrary() {
return gen::map(gen::arbitrary<std::int32_t>(),
[](std::int32_t raw) { return fp_t::from_raw(raw); });
}
};
}
TEST_CASE("fp_t addition is commutative for any bit pattern (fuzzed)") {
rc::prop("a + b == b + a",
[](const fp_t& a, const fp_t& b) {
RC_ASSERT(a + b == b + a);
});
}
TEST_CASE("fp_t multiplication is commutative for any bit pattern (fuzzed)") {
rc::prop("a * b == b * a",
[](const fp_t&a, const fp_t& b) {
RC_ASSERT(a * b == b * a);
});
}
TEST_CASE("fp_t division by itself is identity for any nonzero value (fuzzed)") {
rc::prop("a / a == from_int(1) when a.raw != 0",
[](const fp_t& a) {
RC_PRE(a.raw != 0);
RC_ASSERT(a / a == fp_t::from_int(1));
});
}
|