Agreed, I added a check and more comments on the page: https://tttapa.github.io/Pages/Mathe...implementation

You can now verify the range:

As mentioned by Nominal Animal, a 32-bit state is much slower on an 8-bit MCU, and since a common use is to filter 10-bit analogRead values with a relatively small K, a 16-bit state is preferable.Code:EMA<5, int_fast16_t> filter; static_assert(filter.supports_range(-1024, 1023), "use a wider state or input type, or a smaller shift factor");

I don't think this is an issue, especially if you explicitly cast the input to state_t before adding it. Even if you don't cast it, you're probably fine thanks to theusual arithmetic conversions:

Since the rank of the state type is never less than the rank of the input type, and since the state type is unsigned, the input will be converted to the unsigned state type before performing the addition.[...]

Otherwise, the operand has integer type and integral conversions are applied to produce the common type, as follows:

- If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank

-Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.

- Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type

- Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type.

The conversion rank above increases in order bool, signed char, short, int, long, long long. The rank of any unsigned type is equal to the rank of the corresponding signed type.

The conversion from a signed integer to an unsigned integer effectively sign extends the integer to the full size of the unsigned type because ofintegral promotion:

Once the type is converted, the C and C++ standards guarantee 2ⁿ modular arithmetic for unsigned types, so it's fine.If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2ⁿ where n is the number of bits used to represent the destination type.

The rules apply to the number of bits used to represent the type, which could be 32, for uint_fast16_t on ARM, for example.

uint_fast16_t doesn't guarantee arithmetic modulo 2¹⁶, but it does guarantee arithmetic modulosome power of two.