summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbatsumaru <>2026-08-09 17:26:31 +0900
committerbatsumaru <>2026-08-09 17:26:31 +0900
commit653ebf6675f42dde3cbda1fc088f84a7264ec013 (patch)
tree945dd971842b07ac9982c5a6f94356253c67c2b6
parent7bb49794297b46aa1c577e89da24d39b4348c6d4 (diff)
Added fp_t division
-rw-r--r--include/fixed_point.h1
-rw-r--r--src/fixed_point.cpp29
-rw-r--r--tests/test_fixed_point.cpp46
3 files changed, 70 insertions, 6 deletions
diff --git a/include/fixed_point.h b/include/fixed_point.h
index ff8e2b3..9df6376 100644
--- a/include/fixed_point.h
+++ b/include/fixed_point.h
@@ -15,6 +15,7 @@ struct fp_t {
fp_t operator+(const fp_t& other) const;
fp_t operator-(const fp_t& other) const;
fp_t operator*(const fp_t& other) const;
+ fp_t operator/(const fp_t& other) const;
bool operator==(const fp_t& other) const;
};
diff --git a/src/fixed_point.cpp b/src/fixed_point.cpp
index 847a5f7..8b4b937 100644
--- a/src/fixed_point.cpp
+++ b/src/fixed_point.cpp
@@ -1,22 +1,39 @@
#include "fixed_point.h"
+#include <cstdlib>
+#include <cstdio>
fp_t fp_t::operator+(const fp_t& other) const {
- return {(int32_t)((uint32_t)raw + (uint32_t)other.raw)};
+ return {(std::int32_t)((std::uint32_t)raw + (std::uint32_t)other.raw)};
}
fp_t fp_t::operator-(const fp_t& other) const {
- return {(int32_t)((uint32_t)raw - (uint32_t)other.raw)};
+ return {(std::int32_t)((std::uint32_t)raw - (std::uint32_t)other.raw)};
}
fp_t fp_t::operator*(const fp_t& other) const {
- int32_t result;
- int64_t temp;
- temp = (int64_t)raw * (int64_t)other.raw;
+ std::int32_t result;
+ std::int64_t temp;
+ temp = (std::int64_t)raw * (std::int64_t)other.raw;
temp += fp_t::K;
- result = (int32_t)(temp >> fp_t::Q);
+ result = (std::int32_t)(temp >> fp_t::Q);
return {result};
}
+fp_t fp_t::operator/(const fp_t& other) const {
+ if (other.raw == 0) {
+ std::fprintf(stderr, "fp_t: division by zero\n");
+ std::abort();
+ }
+ std::int64_t temp = (std::int64_t)raw << fp_t::Q;
+
+ if ((temp >= 0 && other.raw >= 0) || (temp < 0 && other.raw < 0)) {
+ temp += (other.raw / 2);
+ } else {
+ temp -= (other.raw / 2);
+ }
+ return {(std::int32_t)(temp / other.raw)};
+}
+
bool fp_t::operator==(const fp_t& other) const {
return raw == other.raw;
}
diff --git a/tests/test_fixed_point.cpp b/tests/test_fixed_point.cpp
index 6d1a594..8c5c269 100644
--- a/tests/test_fixed_point.cpp
+++ b/tests/test_fixed_point.cpp
@@ -50,3 +50,49 @@ TEST_CASE("fp_t multiplication drops percision under 1 ULP") {
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);
+}