diff --git a/src/modm/math/saturated/saturated.hpp b/src/modm/math/saturated/saturated.hpp deleted file mode 100644 index 7bd74a6def..0000000000 --- a/src/modm/math/saturated/saturated.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2009-2010, Fabian Greif - * Copyright (c) 2009-2010, Martin Rosekeit - * Copyright (c) 2012, Niklas Hauser - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#ifndef MODM_SATURATED_HPP -#define MODM_SATURATED_HPP - -#include - -namespace modm -{ - /** - * \brief Saturated arithmetics - * - * \see http://www.mikrocontroller.net/articles/AVR_Arithmetik/Saturierung - * - * \author Fabian Greif - * - * \todo extend implementation (multiplication etc.) - * \todo add 16-bit datetype assembler implementations for AVRs - * \todo documentation - * \ingroup modm_math_saturated - */ - template - class Saturated - { - typedef modm::SignedType SignedType; - typedef modm::WideType WideType; - - public: - Saturated(); - - Saturated(const T& initialValue); - - inline const T& - getValue() const - { - return value; - } - - Saturated& - operator += (const Saturated& other); - - Saturated& - operator -= (const Saturated& other); - - void - absolute(); - - public: - template - friend Saturated - operator - (const Saturated& x); - - template - friend Saturated - abs(const Saturated& x); - - template - friend Saturated - operator - (const Saturated& a, const Saturated& b); - - template - friend Saturated - operator + (const Saturated& a, const Saturated& b); - - template - friend bool - operator == (const Saturated& a, const Saturated& b); - - template - friend bool - operator != (const Saturated& a, const Saturated& b); - - // TODO > >= < <= - - private: - void - setValue(WideType value); - - T value; - }; - - // ------------------------------------------------------------------------ - - /// \brief Invert value - template - Saturated - operator - (const Saturated& x); - - /// \brief Calculate the absolute value - template - Saturated - abs(const Saturated& x); - - template - Saturated - operator - (const Saturated& a, const Saturated& b); - - template - Saturated - operator + (const Saturated& a, const Saturated& b); - - template - inline bool - operator == (const Saturated& a, const Saturated& b); - - template - inline bool - operator != (const Saturated& a, const Saturated& b); -} - -#include "saturated_impl.hpp" - -#endif // MODM_SATURATED_HPP diff --git a/src/modm/math/saturated/saturated__avr_s8_impl.hpp b/src/modm/math/saturated/saturated__avr_s8_impl.hpp deleted file mode 100644 index b408a901e9..0000000000 --- a/src/modm/math/saturated/saturated__avr_s8_impl.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2009, Fabian Greif - * Copyright (c) 2010, Martin Rosekeit - * Copyright (c) 2012, Niklas Hauser - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#ifndef MODM_SATURATED_HPP - #error "Don't include this file directly use 'math/saturated.hpp' instead!" -#endif - -namespace modm -{ - // ------------------------------------------------------------------------ - template<> - Saturated& - Saturated::operator+=(const Saturated& other) { - asm ( - "add %[x], %[y]" "\n\t" - "brvc 0f" "\n\t" // Falls es einen signed Überlauf gab - // (V=1) Maximalwert laden - "ldi %[x], 0x7f" "\n\t" - "sbrc %[y], 7" "\n\t" // y ist negativ, daher muss der - // Minimalwert geladen werden - "ldi %[x], 0x80" "\n\t" - "0:" - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - } - - // ------------------------------------------------------------------------ - // TODO testen - /*template<> - Saturated& - Saturated::operator+=(const Saturated& other) { - asm ( - "add %[x], %[y]" "\n\t" - "brvc 0f" "\n\t" // Falls es einen signed Überlauf gab - // (V=1) Maximalwert laden - "ldi %[x], 0xff" "\n\t" - "0:" - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - }*/ - - // ------------------------------------------------------------------------ - template<> - Saturated& - Saturated::operator-=(const Saturated& other) { - asm ( - "sub %[x], %[y]" "\n\t" - "brvc 0f" "\n\t" // Falls es einen signed Überlauf gab - // (V=1) Minimalwert laden - "ldi %[x], 0x80" "\n\t" - "sbrc %[y], 7" "\n\t" // y ist negativ, daher muss der - // Maximalwert geladen werden - "ldi %[x], 0x7f" "\n\t" - "0:" - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - } - - // ------------------------------------------------------------------------ - // TODO testen - /*template<> - Saturated& - Saturated::operator-=(const Saturated& other) { - asm ( - "sub %[x], %[y]" "\n\t" - "brvc 0f" "\n\t" // Falls es einen signed Überlauf gab - // (V=1) Minimalwert laden - "ldi %[x], 0x80" "\n\t" - "0:" - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - }*/ - - // ------------------------------------------------------------------------ - // FIXME warum funktioniert das nicht??? - template<> - Saturated - operator - (const Saturated& a) { - Saturated temp(a); - asm ( - "neg %[x]" "\n\t" - "brvc 0f" "\n\t" // Signed Überlauf (V=1): Das Ergebnis - // ist 0x80 und wird verändert zu 0x7f - "dec %[x]" "\n\t" - "0:" - : [x] "+d" (temp.value) - ); - return temp; - } - - // ------------------------------------------------------------------------ - template<> - Saturated - abs(const Saturated& a) { - Saturated temp(a); - asm ( - "sbrc %[x], 7" "\n\t" - "neg %[x]" "\n\t" // x < 0: negieren - "sbrc %[x], 7" "\n\t" - "dec %[x]" "\n\t" // R0 ist immer noch < 0 (also 0x80), - // lade 0x7f - : [x] "+d" (temp.value) - ); - return temp; - } -} diff --git a/src/modm/math/saturated/saturated__avr_u8_impl.hpp b/src/modm/math/saturated/saturated__avr_u8_impl.hpp deleted file mode 100644 index a192fc86bd..0000000000 --- a/src/modm/math/saturated/saturated__avr_u8_impl.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2009, Fabian Greif - * Copyright (c) 2010, Martin Rosekeit - * Copyright (c) 2012, Niklas Hauser - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#ifndef MODM_SATURATED_HPP - #error "Don't include this file directly use 'math/saturated.hpp' instead!" -#endif - -namespace modm -{ - // ------------------------------------------------------------------------ - template<> - Saturated& - Saturated::operator += (const Saturated& other) { - asm ( - "add %[x], %[y]" "\n\t" - "brcc 0f" "\n\t" // Falls es einen unsigned Überlauf gab - // (C=1) Maximalwert laden - "ldi %[x], 0xff" "\n" - "0:" "\n\t" - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - } - - // ------------------------------------------------------------------------ - // Diese Kombination ist am aufwändigsten in der Behandlung und geschieht - // am einfachsten durch Umskalierung auf zwei signed-Werte, - // signed-saturierter Operation und nachfolgender Rückskalierung. Zu - // beachten ist, daß dieser Operator nicht kommutativ ist, d.h. a+b - // liefert i.A. ein anderes Ergebnis als b+a. - /*template<> - Saturated& - Saturated::operator += (const Saturated& other) { - asm ( - "subi %[x], 0x80" "\n\t" // Transformation - // [0x00, 0xff] -> [0x80, 0x7f] - "add %[x], %[y]" "\n\t" - "brvc 0f" "\n\t" // Falls es einen signed Überlauf gab - // (V=1) Maximalwert laden - "ldi %[x], 0x7f" "\n\t" - "sbrc %[y], 7" "\n\t" // R0 ist negativ, daher muss der - // Minimalwert geladen werden - "ldi %[x], 0x80" "\n" - "0:" "\n\t" - "subi %[x], 0x80" "\n\t" // Rücktransformation - // [0x80, 0x7f] -> [0x00, 0xff] - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - }*/ - - // ------------------------------------------------------------------------ - template<> - Saturated& - Saturated::operator -= (const Saturated& other) { - asm ( - "sub %[x], %[y]" "\n\t" - "brcc 0f" "\n\t" // Falls es einen unsigned Unterlauf - // gab (C=1) Minimalwert laden - "clr %[x]" "\n\t" - "0:" - : [x] "+r" (this->value) - : [y] "r" (other.value) - ); - - return *this; - } - - // ------------------------------------------------------------------------ - /*template<> - Saturated& - Saturated::operator-=(const Saturated& other) { - asm ( - "subi %[x], 0x80" "\n\t" // Transformation - // [0x00, 0xff] -> [0x80, 0x7f] - "sub %[x], %[y]" "\n\t" - "brvc 0f" "\n\t" // Falls es einen signed Überlauf gab - // (V=1) Minimalwert laden - "ldi %[x], 0x80" "\n\t" - "sbrc %[y], 7" "\n\t" // R0 ist negativ, daher muss der - // Maximalwert geladen werden - "ldi %[x], 0x7f" "\n" - "0:" "\n\t" - "subi %[x], 0x80" "\n\t" // Rücktransformation - // [0x80, 0x7f] -> [0x00, 0xff] - : [x] "+d" (this->value) - : [y] "r" (other.value) - ); - - return *this; - }*/ -} diff --git a/src/modm/math/saturated/saturated_impl.hpp b/src/modm/math/saturated/saturated_impl.hpp deleted file mode 100644 index edc402336f..0000000000 --- a/src/modm/math/saturated/saturated_impl.hpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2009-2010, Fabian Greif - * Copyright (c) 2010, Martin Rosekeit - * Copyright (c) 2012, 2014, Niklas Hauser - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#ifndef MODM_SATURATED_HPP - #error "Don't include this file directly use 'math/saturated.hpp' instead!" -#endif - -#ifdef __AVR__ - // include faster implementations written in assembler - #include "saturated__avr_u8_impl.hpp" - #include "saturated__avr_s8_impl.hpp" -#endif - -namespace modm -{ - template - Saturated::Saturated() : - value() - { - } - - template - Saturated::Saturated(const T& initialValue) : - value(initialValue) - { - } - - template - void - Saturated::setValue(WideType in) - { - if (in > std::numeric_limits::max()) { - value = std::numeric_limits::max(); - } - else if (in < std::numeric_limits::min()) { - value = std::numeric_limits::min(); - } - else { - value = static_cast(in); - } - } - - template - Saturated& - Saturated::operator += (const Saturated& other) - { - WideType temp = static_cast(this->value) + - static_cast(other.value); - setValue(temp); - - return *this; - } - - template - Saturated& - Saturated::operator -= (const Saturated& other) - { - WideType temp = static_cast(value) - - static_cast(other.value); - setValue(temp); - - return *this; - } - - template - void - Saturated::absolute() - { - if (std::is_signed_v) - { - if (value < 0) { - value = -value; - } - } - } - - // ---------------------------------------------------------------------------- - template - Saturated - operator - (const Saturated& x) - { - using WideType = modm::WideType; - - WideType temp = - static_cast(x.value); - - Saturated result; - result.setValue(temp); - return result; - } - - // ---------------------------------------------------------------------------- - template - Saturated - abs(const Saturated& x) - { - Saturated result(x); - - if (std::is_signed_v) { - result.absolute(); - } - return result; - } - - // ---------------------------------------------------------------------------- - template - Saturated - operator - (const Saturated& a, const Saturated& b) - { - Saturated t(a); - t -= b; - return t; - } - - // ---------------------------------------------------------------------------- - template - Saturated - operator + (const Saturated& a, const Saturated& b) - { - Saturated t(a); - t += b; - return t; - } - - // ---------------------------------------------------------------------------- - template - inline bool - operator == (const Saturated& a, const Saturated& b) - { - return (a.value == b.value); - } - - // ---------------------------------------------------------------------------- - template - inline bool - operator != (const Saturated& a, const Saturated& b) - { - return (a.value != b.value); - } - - // ---------------------------------------------------------------------------- - - template<> - void - Saturated::absolute() - { - } - - template<> - void - Saturated::absolute() - { - } - - template<> - void - Saturated::absolute() - { - } -} diff --git a/src/modm/math/saturation/saturated.hpp b/src/modm/math/saturation/saturated.hpp new file mode 100644 index 0000000000..720370e83b --- /dev/null +++ b/src/modm/math/saturation/saturated.hpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2021, Thomas Sommer + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace modm +{ +/** + * @brief Saturation arithmetic building on 'Integer-Overflow-Builtins' + * Implementation works with integer, unsigned integer and float or reference to them. + * Operators work with the same types or Saturated types of them. + * @see https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html + * @see https://en.wikipedia.org/wiki/Saturation_arithmetic + * + * @author Thomas Sommer + * + * @ingroup modm_math_saturated + */ + +template +requires std::integral> +class Saturated +{ +protected: + using TP = std::remove_reference_t; + using TS = std::conditional_t, T, std::make_signed_t>>; + + T value = 0; +private: + static constexpr TP min = std::numeric_limits::min(); + static constexpr TP max = std::numeric_limits::max(); + +public: + Saturated() = default; + + constexpr Saturated(const T& value) : value(value){}; + constexpr Saturated(const Saturated& other) : value(other.value){}; + + template + requires std::integral> + constexpr Saturated(const U& v) + { value = std::clamp< modm::fits_any_t >(v, min, max); } + + template + requires std::floating_point> + constexpr Saturated(const U& v) + { value = std::clamp(v, min, max); } + + template + requires std::integral> + constexpr Saturated(const Saturated& other) + { value = std::clamp< modm::fits_any_t >(other.value, min, max); } + + TP + getValue() const + { return value; } + + // operator= + void + operator=(const Saturated& other) + { value = other.value; } + + template + requires std::integral> + void + operator=(const Saturated& other) + { value = std::clamp< modm::fits_any_t >(other.value, min, max); } + + // Conversions to underlying type + operator T&() { return value; } + operator T() const { return value; } + + // Postincrement: operator++, operator-- + Saturated& + operator++() + { + if (value < max) value++; + return *this; + } + + Saturated& + operator--() + { + if (value > min) value--; + return *this; + } + + // Preincrement: operator++(int), operator--(int) + Saturated + operator++(int) + { + Saturated tmp(*this); + if (value < max) value++; + return tmp; + } + + Saturated + operator--(int) + { + Saturated tmp(*this); + if (value > min) value--; + return tmp; + } + + // Negation: operator- + TS + operator-() + { + // Dump negation. Does not std::clamp. + return -TS(value); + } + + // operator+=, operator-=, operator*= + template + requires std::unsigned_integral> + Saturated& + operator+=(const Saturated& other) + { + if (__builtin_add_overflow(value, other.value, &value)) + value = max; + + return *this; + } + + template + requires std::signed_integral> + Saturated& + operator+=(const Saturated& other) + { + if (other.value < 0) { + if (__builtin_sub_overflow(value, -other.value, &value)) + value = min; + } else { + if (__builtin_add_overflow(value, other.value, &value)) + value = max; + } + return *this; + } + + template + requires std::unsigned_integral> + Saturated& + operator-=(const Saturated& other) + { + if (__builtin_sub_overflow(value, other.value, &value)) + value = min; + + return *this; + } + + template + requires std::signed_integral> + Saturated& + operator-=(const Saturated& other) + { + if (other.value < 0) { + if (__builtin_add_overflow(value, -other.value, &value)) + value = max; + } else { + if (__builtin_sub_overflow(value, other.value, &value)) + value = min; + } + + return *this; + } + + template + requires std::unsigned_integral> + Saturated& + operator*=(const Saturated& other) + { + if (__builtin_mul_overflow(value, other.value, &value)) + value = max; + + return *this; + } + + template + requires std::signed_integral> + Saturated& + operator*=(const Saturated& other) + { + if (other.value < 0) { + if (__builtin_mul_overflow(value, -other.value, &value)) + value = max; + value = -value; + } else { + if (__builtin_mul_overflow(value, other.value, &value)) + value = max; + } + + return *this; + } + + // OPTIMIZE By whatever reason, for operator*= the compiler can't imlicitly construct Saturated types + // like for any other operator above. Need to overload for plain types to suite any case. + template + requires std::unsigned_integral> + Saturated& + operator*=(const U& v) + { + if (__builtin_mul_overflow(value, v, &value)) + value = max; + + return *this; + } + + template + requires std::signed_integral> + Saturated& + operator*=(const U& v) + { + if (v < 0) { + // FIXME unfinished business !? + if (__builtin_mul_overflow(value, -v, &value)) + value = max; + value = -value; + } else { + if (__builtin_mul_overflow(value, v, &value)) + value = max; + } + + return *this; + } + + // operator+, operator-, operator* + template + requires std::unsigned_integral> + TP + operator+(const Saturated& other) + { + Saturated tmp; + + if (__builtin_add_overflow(value, other.value, &tmp.value)) + tmp.value = max; + + return tmp.value; + } + + template + requires std::signed_integral> + TP + operator+(const Saturated& other) + { + Saturated tmp; + + if (other.value < 0) { + if (__builtin_sub_overflow(value, -other.value, &tmp.value)) + tmp.value = min; + } else { + if (__builtin_add_overflow(value, other.value, &tmp.value)) + tmp.value = max; + } + + return tmp.value; + } + + template + requires std::unsigned_integral> + TP + operator-(const Saturated& other) + { + Saturated tmp; + + if (__builtin_sub_overflow(value, other.value, &tmp.value)) + tmp.value = min; + + return tmp.value; + } + + template + requires std::signed_integral> + TP + operator-(const Saturated& other) + { + Saturated tmp; + + if (other.value < 0) { + if (__builtin_add_overflow(value, -other.value, &tmp.value)) + tmp.value = max; + } else { + if (__builtin_sub_overflow(value, other.value, &tmp.value)) + tmp.value = min; + } + + return tmp.value; + } + + TP + operator*(const Saturated& other) + { + Saturated tmp; + + if (__builtin_mul_overflow(value, other.value, &tmp.value)) + tmp.value = max; + + return tmp.value; + } + + void + absolute() + { + value = std::abs(value); + } + + constexpr auto + operator<=>(const Saturated&) const = default; + + template + friend class Saturated; +}; + +} // namespace modm \ No newline at end of file diff --git a/src/modm/math/saturated/module.lb b/src/modm/math/saturation/saturation.lb similarity index 74% rename from src/modm/math/saturated/module.lb rename to src/modm/math/saturation/saturation.lb index 460f61732e..70dc85992f 100644 --- a/src/modm/math/saturated/module.lb +++ b/src/modm/math/saturation/saturation.lb @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright (c) 2018, Niklas Hauser +# Copyright (c) 2018, Thomas Sommer # # This file is part of the modm project. # @@ -11,13 +11,13 @@ # ----------------------------------------------------------------------------- def init(module): - module.name = ":math:saturated" - module.description = "Saturated Arithmetics" + module.name = ":math:saturation" + module.description = "Saturation Arithmetics" def prepare(module, options): module.depends(":math:utils") return True def build(env): - env.outbasepath = "modm/src/modm/math/saturated" + env.outbasepath = "modm/src/modm/math/saturation" env.copy(".") diff --git a/src/modm/math/utils/integer_traits.hpp b/src/modm/math/utils/integer_traits.hpp new file mode 100644 index 0000000000..68c0fbba9b --- /dev/null +++ b/src/modm/math/utils/integer_traits.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021, Thomas Sommer + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include + +#include +namespace modm +{ + +/** + * @brief Trait the smallest unsigned type that fits n Bits + * @author Thomas Sommer + */ +template +struct uint_t +{ + using least = std::conditional_t< + (Bits <= 8), uint8_t, std::conditional_t< + (Bits <= 16), uint16_t, std::conditional_t< + (Bits <= 32), uint32_t, std::enable_if_t< + (Bits <= 64), uint64_t>>>>; +}; + +template +using least_uint = typename modm::uint_t::least; + +namespace detail { + template + constexpr int most_digits() { + return std::numeric_limits::digits; + } + + template + constexpr std::enable_if_t + most_digits() { + return std::max(std::numeric_limits::digits, most_digits()); + } +} + +/** + * @brief Trait the smallest integral - signed or unsigned - fitting any Ts + * @author Thomas Sommer + */ +template +struct fits_any { + static constexpr int most_dig = detail::most_digits(); + + using type = std::conditional_t< + std::conjunction_v...>, + typename uint_t::least, + // An odd most_dig means: type with most digits is signed integral + std::make_signed_t::least> + >; +}; + +template + using fits_any_t = typename fits_any::type; +} \ No newline at end of file diff --git a/test/modm/math/module.lb b/test/modm/math/module.lb index 90f8744bff..fbb8799ef3 100644 --- a/test/modm/math/module.lb +++ b/test/modm/math/module.lb @@ -20,7 +20,7 @@ def prepare(module, options): "modm:math:filter", "modm:math:geometry", "modm:math:interpolation", - "modm:math:saturated", + "modm:math:saturation", "modm:math:matrix", "modm:math:algorithm", "modm:math:utils") diff --git a/test/modm/math/saturated/saturated_test.cpp b/test/modm/math/saturated/saturated_test.cpp deleted file mode 100644 index 52abe31590..0000000000 --- a/test/modm/math/saturated/saturated_test.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2009, Martin Rosekeit - * Copyright (c) 2009-2010, Fabian Greif - * Copyright (c) 2012, Niklas Hauser - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#include - -#include "saturated_test.hpp" - -void -SaturatedTest::testSigned8bit() -{ - //TEST_FAIL("TODO"); - -} - -void -SaturatedTest::testUnsigned8bit() -{ - modm::Saturated x; - modm::Saturated y(100); - - TEST_ASSERT_EQUALS(x.getValue(), 0); - TEST_ASSERT_EQUALS(y.getValue(), 100); - - x = 200; - - TEST_ASSERT_EQUALS(x.getValue(), 200); - - x += y; - - TEST_ASSERT_EQUALS(x.getValue(), 255); - - x = 10; - y = 20; - x -= y; - - TEST_ASSERT_EQUALS(x.getValue(), 0); - - modm::Saturated z; - - x = 20; - y = 10; - - z = x + y; - - TEST_ASSERT_EQUALS(x.getValue(), 20); - TEST_ASSERT_EQUALS(y.getValue(), 10); - TEST_ASSERT_EQUALS(z.getValue(), 30); - - z = x - y; - - TEST_ASSERT_EQUALS(x.getValue(), 20); - TEST_ASSERT_EQUALS(y.getValue(), 10); - TEST_ASSERT_EQUALS(z.getValue(), 10); - - y = z - x; - - TEST_ASSERT_EQUALS(x.getValue(), 20); - TEST_ASSERT_EQUALS(y.getValue(), 0); - TEST_ASSERT_EQUALS(z.getValue(), 10); - - x = -z; - - TEST_ASSERT_EQUALS(x.getValue(), 0); - - y = 200; - //x = abs(y); - x = y; - x.absolute(); - - TEST_ASSERT_EQUALS(x.getValue(), 200); -} diff --git a/test/modm/math/saturation/saturation_test.cpp b/test/modm/math/saturation/saturation_test.cpp new file mode 100644 index 0000000000..98460796bc --- /dev/null +++ b/test/modm/math/saturation/saturation_test.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2009, Martin Rosekeit + * Copyright (c) 2009-2010, Fabian Greif + * Copyright (c) 2012, Niklas Hauser + * Copyright (c) 2021, Thomas Sommer + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include + +#include "saturation_test.hpp" +#include + +void +SaturationTest::testSigned8bit() +{ + modm::Saturated x; + modm::Saturated y(100); + + TEST_ASSERT_EQUALS(x.getValue(), 0); + TEST_ASSERT_EQUALS(y.getValue(), 100); + + x = 110; + + TEST_ASSERT_EQUALS(x.getValue(), 110); + + x += y; + + TEST_ASSERT_EQUALS(x.getValue(), 127); + + x = -100; + y = 50; + x -= y; + + TEST_ASSERT_EQUALS(x.getValue(), -128); + + modm::Saturated z; + + x = 20; + y = 10; + + z = x + y; + + TEST_ASSERT_EQUALS(x.getValue(), 20); + TEST_ASSERT_EQUALS(y.getValue(), 10); + TEST_ASSERT_EQUALS(z.getValue(), 30); + + z = x - y; + + TEST_ASSERT_EQUALS(x.getValue(), 20); + TEST_ASSERT_EQUALS(y.getValue(), 10); + TEST_ASSERT_EQUALS(z.getValue(), 10); + + y = z - x; + + TEST_ASSERT_EQUALS(x.getValue(), 20); + TEST_ASSERT_EQUALS(y.getValue(), 0); + TEST_ASSERT_EQUALS(z.getValue(), 10); + + x = -z; + + TEST_ASSERT_EQUALS(x.getValue(), -10); + + /* y = -100; + x = std::abs(y); + TEST_ASSERT_EQUALS(x.getValue(), 100); + + x = y; + x.absolute(); + TEST_ASSERT_EQUALS(x.getValue(), 100); */ +} + +void +SaturationTest::testUnsigned8bit() +{ + modm::Saturated x; + modm::Saturated y(100); + + TEST_ASSERT_EQUALS(x.getValue(), 0); + TEST_ASSERT_EQUALS(y.getValue(), 100); + + x = 200; + + TEST_ASSERT_EQUALS(x.getValue(), 200); + + x += y; + + TEST_ASSERT_EQUALS(x.getValue(), 255); + + x = 10; + y = 20; + x -= y; + + TEST_ASSERT_EQUALS(x.getValue(), 0); + + x = 100; + y = 3; + x *= y; + + TEST_ASSERT_EQUALS(x.getValue(), 255); + + modm::Saturated z; + + x = 20; + y = 10; + + z = x + y; + + TEST_ASSERT_EQUALS(x.getValue(), 20); + TEST_ASSERT_EQUALS(y.getValue(), 10); + TEST_ASSERT_EQUALS(z.getValue(), 30); + + z = x - y; + + TEST_ASSERT_EQUALS(x.getValue(), 20); + TEST_ASSERT_EQUALS(y.getValue(), 10); + TEST_ASSERT_EQUALS(z.getValue(), 10); + + y = z - x; + + TEST_ASSERT_EQUALS(x.getValue(), 20); + TEST_ASSERT_EQUALS(y.getValue(), 0); + TEST_ASSERT_EQUALS(z.getValue(), 10); + + x = -z; + + TEST_ASSERT_EQUALS(x.getValue(), 0); + + y = 200; + x = std::abs(y); + TEST_ASSERT_EQUALS(x.getValue(), 200); + + x = y; + x.absolute(); + TEST_ASSERT_EQUALS(x.getValue(), 200); +} + +void +SaturationTest::testSigned16bit() +{ + modm::Saturated x; + modm::Saturated y(30000); + + TEST_ASSERT_EQUALS(x.getValue(), 0); + TEST_ASSERT_EQUALS(y.getValue(), 30000); + + x = 20000; + + TEST_ASSERT_EQUALS(x.getValue(), 20000); + + x += y; + + TEST_ASSERT_EQUALS(x.getValue(), 32767); + + x = 1000; + y = 2000; + x -= y; + + TEST_ASSERT_EQUALS(x.getValue(), -1000); + + modm::Saturated z; + + x = 10000; + y = 20000; + + z = x + y; + + TEST_ASSERT_EQUALS(x.getValue(), 10000); + TEST_ASSERT_EQUALS(y.getValue(), 20000); + TEST_ASSERT_EQUALS(z.getValue(), 30000); + + z = x - y; + + TEST_ASSERT_EQUALS(x.getValue(), 10000); + TEST_ASSERT_EQUALS(y.getValue(), 20000); + TEST_ASSERT_EQUALS(z.getValue(), -10000); + + y = z - x; + + // ??? + TEST_ASSERT_EQUALS(x.getValue(), 10000); + TEST_ASSERT_EQUALS(y.getValue(), -20000); + TEST_ASSERT_EQUALS(z.getValue(), -10000); + + x = -z; + + TEST_ASSERT_EQUALS(x.getValue(), 10000); + + y = -20000; + x = std::abs(y); + TEST_ASSERT_EQUALS(x.getValue(), 20000); + + x = y; + x.absolute(); + TEST_ASSERT_EQUALS(x.getValue(), 20000); +} + +void +SaturationTest::testUnsigned16bit() +{ + modm::Saturated x; + modm::Saturated y(30000); + + TEST_ASSERT_EQUALS(x.getValue(), 0); + TEST_ASSERT_EQUALS(y.getValue(), 30000); + + x = 40000; + + TEST_ASSERT_EQUALS(x.getValue(), 40000); + + x += y; + + TEST_ASSERT_EQUALS(x.getValue(), 65535); + + x = 1000; + y = 2000; + x -= y; + + TEST_ASSERT_EQUALS(x.getValue(), 0); + + x = 20000; + x *= 5; + + TEST_ASSERT_EQUALS(x.getValue(), 65535); + + modm::Saturated z; + + x = 20000; + y = 10000; + + z = x + y; + + TEST_ASSERT_EQUALS(x.getValue(), 20000); + TEST_ASSERT_EQUALS(y.getValue(), 10000); + TEST_ASSERT_EQUALS(z.getValue(), 30000); + + z = x - y; + + TEST_ASSERT_EQUALS(x.getValue(), 20000); + TEST_ASSERT_EQUALS(y.getValue(), 10000); + TEST_ASSERT_EQUALS(z.getValue(), 10000); + + y = z - x; + + TEST_ASSERT_EQUALS(x.getValue(), 20000); + TEST_ASSERT_EQUALS(y.getValue(), 0); + TEST_ASSERT_EQUALS(z.getValue(), 10000); + + x = -z; + + TEST_ASSERT_EQUALS(x.getValue(), 0); + + y = 20000; + x = std::abs(y); + TEST_ASSERT_EQUALS(x.getValue(), 20000); + + x = y; + x.absolute(); + TEST_ASSERT_EQUALS(x.getValue(), 20000); +} \ No newline at end of file diff --git a/test/modm/math/saturated/saturated_test.hpp b/test/modm/math/saturation/saturation_test.hpp similarity index 80% rename from test/modm/math/saturated/saturated_test.hpp rename to test/modm/math/saturation/saturation_test.hpp index e96ede3095..4012c2afea 100644 --- a/test/modm/math/saturated/saturated_test.hpp +++ b/test/modm/math/saturation/saturation_test.hpp @@ -2,6 +2,7 @@ * Copyright (c) 2009, Martin Rosekeit * Copyright (c) 2009-2010, Fabian Greif * Copyright (c) 2012, Niklas Hauser + * Copyright (c) 2021, Thomas Sommer * * This file is part of the modm project. * @@ -14,7 +15,7 @@ #include /// @ingroup modm_test_test_math -class SaturatedTest : public unittest::TestSuite +class SaturationTest : public unittest::TestSuite { public: void @@ -22,4 +23,10 @@ class SaturatedTest : public unittest::TestSuite void testUnsigned8bit(); + + void + testSigned16bit(); + + void + testUnsigned16bit(); };