Skip to content

Commit dfc629b

Browse files
authored
Merge pull request #1758 from Eeelco/master
Add intermediary type to fixed point types
2 parents 1c3f0ea + 5ad6d72 commit dfc629b

File tree

4 files changed

+143
-80
lines changed

4 files changed

+143
-80
lines changed

copying.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ _the openage authors_ are:
163163
| Ngô Xuân Minh | | xminh dawt ngo dawt 00 à gmail dawt com |
164164
| Haytham Tang | haytham918 | yunxuant à umich dawt edu |
165165
| Ana Trias-Labellarte | anatriaslabella | ana dawt triaslabella à ufl dawt edu |
166+
| Eelco Empting | Eeelco | me à eelco dawt de |
166167

167168
If you're a first-time committer, add yourself to the above list. This is not
168169
just for legal reasons, but also to keep an overview of all those nicknames.

libopenage/testing/testing.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2014-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2014-2025 the openage authors. See copying.md for legal info.
22

33
#pragma once
44

@@ -51,7 +51,9 @@ bool fail(const log::message &msg);
5151
try { \
5252
auto &&test_result_left = (left); \
5353
if (test_result_left != (right)) { \
54-
TESTFAILMSG("unexpected value: " << (test_result_left)); \
54+
TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": Expected " \
55+
<< test_result_left << " and " \
56+
<< (right) << " to be equal"); \
5557
} \
5658
} \
5759
catch (::openage::testing::TestError & e) { \
@@ -63,6 +65,28 @@ bool fail(const log::message &msg);
6365
} \
6466
while (0)
6567

68+
/**
69+
* Asserts that the left expression does not equal the right expression,
70+
* and that no exception is thrown.
71+
*/
72+
#define TESTNOTEQUALS(left, right) \
73+
do { \
74+
try { \
75+
auto &&test_result_left = (left); \
76+
if (test_result_left == (right)) { \
77+
TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": Expected " \
78+
<< test_result_left << " and " \
79+
<< (right) << " to be NOT equal"); \
80+
} \
81+
} \
82+
catch (::openage::testing::TestError & e) { \
83+
throw; \
84+
} \
85+
catch (::openage::error::Error & e) { \
86+
TESTFAILMSG("unexpected exception: " << e); \
87+
} \
88+
} \
89+
while (0)
6690

6791
/**
6892
* Asserts that the left expression equals the right expression,
@@ -72,8 +96,9 @@ bool fail(const log::message &msg);
7296
do { \
7397
try { \
7498
auto &&test_result_left = (left); \
75-
if ((test_result_left < (right - epsilon)) or (test_result_left > (right + epsilon))) { \
76-
TESTFAILMSG("unexpected value: " << (test_result_left)); \
99+
auto &&test_result_right = (right); \
100+
if ((test_result_left < (test_result_right - epsilon)) or (test_result_left > (test_result_right + epsilon))) { \
101+
TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": Expected " << (test_result_left) << " and " << (test_result_right) << " to be equal"); \
77102
} \
78103
} \
79104
catch (::openage::testing::TestError & e) { \
@@ -99,7 +124,7 @@ bool fail(const log::message &msg);
99124
expr_has_thrown = true; \
100125
} \
101126
if (not expr_has_thrown) { \
102-
TESTFAILMSG("no exception"); \
127+
TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": no exception"); \
103128
} \
104129
} \
105130
while (0)
@@ -114,7 +139,7 @@ bool fail(const log::message &msg);
114139
expression; \
115140
} \
116141
catch (::openage::error::Error & e) { \
117-
TESTFAILMSG("unexpected exception"); \
142+
TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": unexpected exception"); \
118143
} \
119144
} \
120145
while (0)

libopenage/util/fixed_point.h

Lines changed: 76 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,16 @@ constexpr static
8585
* If you change this class, remember to update the gdb pretty printers
8686
* in etc/gdb_pretty/printers.py.
8787
*/
88-
template <typename int_type, unsigned int fractional_bits>
88+
template <typename int_type, unsigned int fractional_bits, typename intermediate_type = int_type>
8989
class FixedPoint {
9090
public:
9191
using raw_type = int_type;
92-
using this_type = FixedPoint<int_type, fractional_bits>;
92+
using this_type = FixedPoint<int_type, fractional_bits, intermediate_type>;
9393
using unsigned_int_type = typename std::make_unsigned<int_type>::type;
94+
using unsigned_intermediate_type = typename std::make_unsigned<intermediate_type>::type;
95+
9496
using same_type_but_unsigned = FixedPoint<typename FixedPoint::unsigned_int_type,
95-
fractional_bits>;
97+
fractional_bits, typename FixedPoint::unsigned_intermediate_type>;
9698

9799
private:
98100
// Helper function to create the scaling factors that are used below.
@@ -264,14 +266,14 @@ class FixedPoint {
264266
/**
265267
* Factory function to get a fixed-point number from a fixed-point number of different type.
266268
*/
267-
template <typename other_int_type, unsigned int other_fractional_bits, typename std::enable_if<(fractional_bits > other_fractional_bits)>::type * = nullptr>
268-
static constexpr FixedPoint from_fixedpoint(const FixedPoint<other_int_type, other_fractional_bits> &other) {
269+
template <typename other_int_type, unsigned int other_fractional_bits, typename other_intermediate_type, typename std::enable_if<(fractional_bits > other_fractional_bits)>::type * = nullptr>
270+
static constexpr FixedPoint from_fixedpoint(const FixedPoint<other_int_type, other_fractional_bits, other_intermediate_type> &other) {
269271
return FixedPoint::from_raw_value(
270272
safe_shift<fractional_bits - other_fractional_bits, int_type>(static_cast<int_type>(other.get_raw_value())));
271273
}
272274

273-
template <typename other_int_type, unsigned int other_fractional_bits, typename std::enable_if<(fractional_bits <= other_fractional_bits)>::type * = nullptr>
274-
static constexpr FixedPoint from_fixedpoint(const FixedPoint<other_int_type, other_fractional_bits> &other) {
275+
template <typename other_int_type, unsigned int other_fractional_bits, typename other_intermediate_type, typename std::enable_if<(fractional_bits <= other_fractional_bits)>::type * = nullptr>
276+
static constexpr FixedPoint from_fixedpoint(const FixedPoint<other_int_type, other_fractional_bits, other_intermediate_type> &other) {
275277
return FixedPoint::from_raw_value(
276278
static_cast<int_type>(other.get_raw_value() / safe_shiftleft<other_fractional_bits - fractional_bits, other_int_type>(1)));
277279
}
@@ -380,14 +382,14 @@ class FixedPoint {
380382
return FixedPoint::this_type::from_raw_value(-this->raw_value);
381383
}
382384

383-
template <typename I, unsigned F>
384-
constexpr double hypot(const FixedPoint<I, F> rhs) {
385+
template <typename I, unsigned F, typename Inter>
386+
constexpr double hypot(const FixedPoint<I, F, Inter> rhs) {
385387
return std::hypot(this->to_double(), rhs.to_double());
386388
}
387389

388-
template <typename I, unsigned F>
389-
constexpr FixedPoint<I, F> hypotfp(const FixedPoint<I, F> rhs) {
390-
return FixedPoint<I, F>(this->hypot(rhs));
390+
template <typename I, unsigned F, typename Inter>
391+
constexpr FixedPoint<I, F> hypotfp(const FixedPoint<I, F, Inter> rhs) {
392+
return FixedPoint<I, F, Inter>(this->hypot(rhs));
391393
}
392394

393395
// Basic operators
@@ -471,42 +473,42 @@ class FixedPoint {
471473
/**
472474
* FixedPoint + FixedPoint
473475
*/
474-
template <typename I, unsigned int F>
475-
constexpr FixedPoint<I, F> operator+(const FixedPoint<I, F> &lhs, const FixedPoint<I, F> &rhs) {
476-
return FixedPoint<I, F>::from_raw_value(lhs.get_raw_value() + rhs.get_raw_value());
476+
template <typename I, unsigned int F, typename Inter>
477+
constexpr FixedPoint<I, F, Inter> operator+(const FixedPoint<I, F, Inter> &lhs, const FixedPoint<I, F, Inter> &rhs) {
478+
return FixedPoint<I, F, Inter>::from_raw_value(lhs.get_raw_value() + rhs.get_raw_value());
477479
}
478480

479481
/**
480482
* FixedPoint + double
481483
*/
482-
template <typename I, unsigned int F>
483-
constexpr FixedPoint<I, F> operator+(const FixedPoint<I, F> &lhs, const double &rhs) {
484-
return FixedPoint<I, F>{lhs} + FixedPoint<I, F>::from_double(rhs);
484+
template <typename I, unsigned int F, typename Inter>
485+
constexpr FixedPoint<I, F, Inter> operator+(const FixedPoint<I, F, Inter> &lhs, const double &rhs) {
486+
return FixedPoint<I, F, Inter>{lhs} + FixedPoint<I, F, Inter>::from_double(rhs);
485487
}
486488

487489
/**
488490
* FixedPoint - FixedPoint
489491
*/
490-
template <typename I, unsigned int F>
491-
constexpr FixedPoint<I, F> operator-(const FixedPoint<I, F> &lhs, const FixedPoint<I, F> &rhs) {
492-
return FixedPoint<I, F>::from_raw_value(lhs.get_raw_value() - rhs.get_raw_value());
492+
template <typename I, unsigned int F, typename Inter>
493+
constexpr FixedPoint<I, F, Inter> operator-(const FixedPoint<I, F, Inter> &lhs, const FixedPoint<I, F, Inter> &rhs) {
494+
return FixedPoint<I, F, Inter>::from_raw_value(lhs.get_raw_value() - rhs.get_raw_value());
493495
}
494496

495497
/**
496498
* FixedPoint - double
497499
*/
498-
template <typename I, unsigned int F>
499-
constexpr FixedPoint<I, F> operator-(const FixedPoint<I, F> &lhs, const double &rhs) {
500-
return FixedPoint<I, F>{lhs} - FixedPoint<I, F>::from_double(rhs);
500+
template <typename I, unsigned int F, typename Inter>
501+
constexpr FixedPoint<I, F, Inter> operator-(const FixedPoint<I, F, Inter> &lhs, const double &rhs) {
502+
return FixedPoint<I, F, Inter>{lhs} - FixedPoint<I, F, Inter>::from_double(rhs);
501503
}
502504

503505

504506
/**
505507
* FixedPoint * N
506508
*/
507-
template <typename I, unsigned F, typename N>
508-
typename std::enable_if<std::is_arithmetic<N>::value, FixedPoint<I, F>>::type constexpr operator*(const FixedPoint<I, F> lhs, const N &rhs) {
509-
return FixedPoint<I, F>::from_raw_value(lhs.get_raw_value() * rhs);
509+
template <typename I, unsigned F, typename Inter, typename N>
510+
typename std::enable_if<std::is_arithmetic<N>::value, FixedPoint<I, F, Inter>>::type constexpr operator*(const FixedPoint<I, F, Inter> lhs, const N &rhs) {
511+
return FixedPoint<I, F, Inter>::from_raw_value(lhs.get_raw_value() * rhs);
510512
}
511513

512514
/*
@@ -523,40 +525,41 @@ typename std::enable_if<std::is_arithmetic<N>::value, FixedPoint<I, F>>::type co
523525
* => a * a will overflow because:
524526
* a.rawvalue == 2^(16+16) == 2^32
525527
* -> a.rawvalue * a.rawvalue == 2^64 => pwnt
528+
*
529+
* Use a larger intermediate type to prevent overflow
526530
*/
527-
// template <typename I, unsigned int F>
528-
// constexpr FixedPoint<I, F> operator*(const FixedPoint<I, F> lhs, const FixedPoint<I, F> rhs) {
529-
// I ret = 0;
530-
// if (not __builtin_mul_overflow(lhs.get_raw_value(), rhs.get_raw_value(), &ret)) {
531-
// throw std::overflow_error("FixedPoint multiplication overflow");
532-
// }
531+
template <typename I, unsigned int F, typename Inter>
532+
constexpr FixedPoint<I, F, Inter> operator*(const FixedPoint<I, F, Inter> lhs, const FixedPoint<I, F, Inter> rhs) {
533+
Inter ret = static_cast<Inter>(lhs.get_raw_value()) * static_cast<Inter>(rhs.get_raw_value());
534+
ret >>= F;
533535

534-
// return FixedPoint<I, F>::from_raw_value(ret);
535-
// }
536+
return FixedPoint<I, F, Inter>::from_raw_value(static_cast<I>(ret));
537+
}
536538

537539

538540
/**
539541
* FixedPoint / FixedPoint
540542
*/
541-
template <typename I, unsigned int F>
542-
constexpr FixedPoint<I, F> operator/(const FixedPoint<I, F> lhs, const FixedPoint<I, F> rhs) {
543-
return FixedPoint<I, F>::from_raw_value(div(lhs.get_raw_value(), rhs.get_raw_value()) << F);
543+
template <typename I, unsigned int F, typename Inter>
544+
constexpr FixedPoint<I, F, Inter> operator/(const FixedPoint<I, F, Inter> lhs, const FixedPoint<I, F, Inter> rhs) {
545+
Inter ret = div((static_cast<Inter>(lhs.get_raw_value()) << F), static_cast<Inter>(rhs.get_raw_value()));
546+
return FixedPoint<I, F, Inter>::from_raw_value(static_cast<I>(ret));
544547
}
545548

546549

547550
/**
548551
* FixedPoint / N
549552
*/
550-
template <typename I, unsigned F, typename N>
551-
constexpr FixedPoint<I, F> operator/(const FixedPoint<I, F> lhs, const N &rhs) {
552-
return FixedPoint<I, F>::from_raw_value(div(lhs.get_raw_value(), static_cast<I>(rhs)));
553+
template <typename I, unsigned F, typename Inter, typename N>
554+
constexpr FixedPoint<I, F, Inter> operator/(const FixedPoint<I, F, Inter> lhs, const N &rhs) {
555+
return FixedPoint<I, F, Inter>::from_raw_value(div(lhs.get_raw_value(), static_cast<I>(rhs)));
553556
}
554557

555558
/**
556559
* FixedPoint % FixedPoint (modulo)
557560
*/
558-
template <typename I, unsigned int F>
559-
constexpr FixedPoint<I, F> operator%(const FixedPoint<I, F> lhs, const FixedPoint<I, F> rhs) {
561+
template <typename I, unsigned int F, typename Inter>
562+
constexpr FixedPoint<I, F, Inter> operator%(const FixedPoint<I, F, Inter> lhs, const FixedPoint<I, F, Inter> rhs) {
560563
auto div = (lhs / rhs);
561564
auto n = div.to_int();
562565
return lhs - (rhs * n);
@@ -569,71 +572,71 @@ constexpr FixedPoint<I, F> operator%(const FixedPoint<I, F> lhs, const FixedPoin
569572
// std function overloads
570573
namespace std {
571574

572-
template <typename I, unsigned F>
573-
constexpr double sqrt(openage::util::FixedPoint<I, F> n) {
575+
template <typename I, unsigned F, typename Inter>
576+
constexpr double sqrt(openage::util::FixedPoint<I, F, Inter> n) {
574577
return n.sqrt();
575578
}
576579

577-
template <typename I, unsigned F>
578-
constexpr double atan2(openage::util::FixedPoint<I, F> x, openage::util::FixedPoint<I, F> y) {
580+
template <typename I, unsigned F, typename Inter>
581+
constexpr double atan2(openage::util::FixedPoint<I, F, Inter> x, openage::util::FixedPoint<I, F, Inter> y) {
579582
return x.atan2(y);
580583
}
581584

582-
template <typename I, unsigned F>
583-
constexpr double sin(openage::util::FixedPoint<I, F> n) {
585+
template <typename I, unsigned F, typename Inter>
586+
constexpr double sin(openage::util::FixedPoint<I, F, Inter> n) {
584587
return n.sin();
585588
}
586589

587-
template <typename I, unsigned F>
588-
constexpr double cos(openage::util::FixedPoint<I, F> n) {
590+
template <typename I, unsigned F, typename Inter>
591+
constexpr double cos(openage::util::FixedPoint<I, F, Inter> n) {
589592
return n.cos();
590593
}
591594

592-
template <typename I, unsigned F>
593-
constexpr double tan(openage::util::FixedPoint<I, F> n) {
595+
template <typename I, unsigned F, typename Inter>
596+
constexpr double tan(openage::util::FixedPoint<I, F, Inter> n) {
594597
return n.tan();
595598
}
596599

597-
template <typename I, unsigned F>
598-
constexpr openage::util::FixedPoint<I, F> min(openage::util::FixedPoint<I, F> x, openage::util::FixedPoint<I, F> y) {
599-
return openage::util::FixedPoint<I, F>::from_raw_value(
600+
template <typename I, unsigned F, typename Inter>
601+
constexpr openage::util::FixedPoint<I, F, Inter> min(openage::util::FixedPoint<I, F, Inter> x, openage::util::FixedPoint<I, F, Inter> y) {
602+
return openage::util::FixedPoint<I, F, Inter>::from_raw_value(
600603
std::min(x.get_raw_value(),
601604
y.get_raw_value()));
602605
}
603606

604-
template <typename I, unsigned F>
605-
constexpr openage::util::FixedPoint<I, F> max(openage::util::FixedPoint<I, F> x, openage::util::FixedPoint<I, F> y) {
606-
return openage::util::FixedPoint<I, F>::from_raw_value(
607+
template <typename I, unsigned F, typename Inter>
608+
constexpr openage::util::FixedPoint<I, F, Inter> max(openage::util::FixedPoint<I, F, Inter> x, openage::util::FixedPoint<I, F, Inter> y) {
609+
return openage::util::FixedPoint<I, F, Inter>::from_raw_value(
607610
std::max(x.get_raw_value(),
608611
y.get_raw_value()));
609612
}
610613

611-
template <typename I, unsigned F>
612-
constexpr openage::util::FixedPoint<I, F> abs(openage::util::FixedPoint<I, F> n) {
613-
return openage::util::FixedPoint<I, F>::from_raw_value(
614+
template <typename I, unsigned F, typename Inter>
615+
constexpr openage::util::FixedPoint<I, F, Inter> abs(openage::util::FixedPoint<I, F, Inter> n) {
616+
return openage::util::FixedPoint<I, F, Inter>::from_raw_value(
614617
std::abs(n.get_raw_value()));
615618
}
616619

617-
template <typename I, unsigned F>
618-
constexpr double hypot(openage::util::FixedPoint<I, F> x, openage::util::FixedPoint<I, F> y) {
620+
template <typename I, unsigned F, typename Inter>
621+
constexpr double hypot(openage::util::FixedPoint<I, F, Inter> x, openage::util::FixedPoint<I, F, Inter> y) {
619622
return x.hypot(y);
620623
}
621624

622-
template <typename I, unsigned F>
623-
struct hash<openage::util::FixedPoint<I, F>> {
624-
constexpr size_t operator()(const openage::util::FixedPoint<I, F> &n) const {
625+
template <typename I, unsigned F, typename Inter>
626+
struct hash<openage::util::FixedPoint<I, F, Inter>> {
627+
constexpr size_t operator()(const openage::util::FixedPoint<I, F, Inter> &n) const {
625628
return std::hash<I>{}(n.raw_value);
626629
}
627630
};
628631

629-
template <typename I, unsigned F>
630-
struct numeric_limits<openage::util::FixedPoint<I, F>> {
631-
constexpr static openage::util::FixedPoint<I, F> min() {
632-
return openage::util::FixedPoint<I, F>::min_value();
632+
template <typename I, unsigned F, typename Inter>
633+
struct numeric_limits<openage::util::FixedPoint<I, F, Inter>> {
634+
constexpr static openage::util::FixedPoint<I, F, Inter> min() {
635+
return openage::util::FixedPoint<I, F, Inter>::min_value();
633636
}
634637

635-
constexpr static openage::util::FixedPoint<I, F> max() {
636-
return openage::util::FixedPoint<I, F>::max_value();
638+
constexpr static openage::util::FixedPoint<I, F, Inter> max() {
639+
return openage::util::FixedPoint<I, F, Inter>::max_value();
637640
}
638641
};
639642

0 commit comments

Comments
 (0)