@@ -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 >
8989class FixedPoint {
9090public:
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
9799private:
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
570573namespace 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