If you want a cyclic integer type with

*BITS* bits (minimum 2), set constants

` `*HALF* = 1 << (*BITS - 1*);` `*MASK* = *HALF* - 1;noting that

`(`*HALF* | *MASK*) has all low

*BITS* set.

Then, the signed distance from

*from* to

*to* is

` ((`*to* - *from*) & *MASK*) - ((*to* - *from*) & *HALF*)and will always evaluate to a value in -

*HALF*....

*MASK*, inclusive.

I suggest writing it using a suitable

`int_fast`*N*_t type (

*N*=8, 16, 32, 64, whatever can represent -

*HALF*), and form

` int_fast`*N*_t d = *to* - *from*;` return (d & `*MASK*) - (d & *HALF*);for the signed distance.

For example, with

*BITS*=4,

*HALF*=8,

*MASK*=7:

- Distance from 0 to 7 is +7
- Distance from 7 to 0 is -7
- Distance from 0 to 8 is -8, and distance from 8 to 0 is -8, because halfway is always negative
- Distance from 15 to 0 is +1
- Distance from 0 to 15 is -1

One can use standard operations like addition, subtraction, multiplication and division with such values using

`int`*N*_t or

`int_fast`*N*_t types, as long as

*N* >

*BITS*.

When

*N* ==

*BITS*,

`(int`*N*_t)(*to* - *from*) is the signed distance exactly.

The unsigned distance can be written as

` int_fast`*N*_t d = *to* - *from*;` return (d & `*HALF*) ? half - (d & *MASK*) : (d & *MASK*);which will always return a nonnegative distance in 0..

*HALF*, inclusive.

The test for

*from* <=

*to* (but correctly handling the wrapping) can be written as

` !((`*to* - *from*) & *HALF*)Testing whether

*c* is between

*a* and

*b* (inclusive, correctly handling the wrapping), can be written as

` int_fast`*N*_t ac = (c - a) & (*MASK* | *HALF*);` int_fast`*N*_t cb = (b - c) & (*MASK* | *HALF*);` int_fast`*N*_t ab = (b - a) & *HALF*;` return (!ac) || (!cb) || (ab == (ac & `*HALF*) && ab == (cb & *HALF*));which is equivalent to testing that the order of c,a and b,c are the same as b,a. The

`(!ac)` tests for equality on the lower bound, and

`(!cb)` for equality on the upper bound.

Midway between

*a* and

*b* is easiest to calculate as

` (`*a* + signed_distance(*a*, *b*) / 2) & (*MASK* | *HALF*);In general, interpolating between

*a* and

*b* via

*n*/

*N*,

*N* > 0, can be done via

` (`*a* + (signed_distance(*a*, *b*) * *n*) / *N*)) & (*MASK* | *HALF*);if your intermediate type has sufficient range (enough bits for the temporary product). It yields

*a* when

*n**=0, and **b* when *n*=*N*.

If you have two unsigned integer variables

*from* and

*to* in 0..

*FULL*-1, where

*FULL* is the size of the full range (and not a power of two because for those you want to use the above instead), 2·

*HALF*=

*FULL*, then the signed distance from

*from* to

*to* can be calculated using

` int_fast`*N*_t d = *to* - *from*;` return (d > `*HALF*) ? d - *FULL* :` (d < -`*HALF*) ? d + *FULL* : d;The distance from

*FULL*-1 to 0 is +1, and from 0 to

*FULL*-1 is -1; this too wraps correctly. Assuming inputs are within valid range, the returned value is in -

*HALF*...+

*HALF*, inclusive.

Unsigned distance is just the absolute value of the above, for example

` int_fast`*N*_t d = *to* - *from*;` return (d > `*HALF*) ? *FULL* - d :` (d < -`*HALF*) ? *FULL* + d :` (d < 0) ? -d : d;`For

*from* <=

*to*, you can use

` int_fast`*N*_t d = *to* - *from*;` return (d < -`*HALF*) || (d >= 0 && d <= *HALF*));Midway between

*a* and

*b* can be calculated as

` int_fast`*N*_t d = *a* + signed_distance(*a*, *b*)/2;` return (d < 0) ? d + `*FULL* : (d >= *FULL*) ? d - *FULL* : d;Linear interpolation from

*n*=0 at

*a* to

*n*=

*N* at

*b* is similarly

` int_fast`*N*_t d = *a* + (signed_distance(*a*, *b*) * *n*) / *N*;` return (d < 0) ? d + `*FULL* : (d >= *FULL*) ? d - *FULL* : d;This expression yields 0 if

*from* ==

*to*, 1 if

*from* <

*to*, and 2 if

*from* >

*to*. I call it

`compare(`*from*, *to*):` int_fast`*N*_t d = *to* - *from*;` return (d != 0) + (d >= `*HALF*) + (d > -*HALF* && d < 0);With that, it is easy to check if

*c* is between

*a* and

*b*, assuming they are all in 0..

*FULL*-1:

` return ((compare(`*a*, *c*) | compare(*c*, *b*) | compare(*a*, *b*)) != 3);Essentially, it verifies that c-a and b-c are in the same direction as b-a.

It is possible to combine these two, using low bits for the binary (fractional or angle) part, and upper bits for an arbitrary cyclic range, by simply shifting

*FULL* and

*HALF* left by fractional bits for the combined arbitrary range. (That is, your arbitrary range will have

*FULL* and

*HALF* with at least

*BITS* least significant bits zero.)

To simplify things, one could use full 16 bits for the fractional/angle part (for use with

`uint16_t` or

`uint_fast16_t`), and the leftover 14 bits or so for the integral angle. We need a couple of extra bits, to make sure the integral part can represent values in -

*FULL*..2*

*FULL*-1, inclusive. The angular precision is then 360°/65536 = 45°/8192 = 0.0054931640625°, or 10125/512 = 19.775390625 arcseconds. For sines and cosines, you need a quarter wave, which here would be split into 16384 steps.

A suitable value for the integral number of turns would be 16380 = 65·252 = 2340·7. On architectures with an unsigned 32-bit by 32-bit multiplication returning the upper 32 bits, compilers can optimize "(uint32_t)(x) % 16380" and "(uint16_t)(x) % 16380" to one multiplication, some bit shifts and a couple of additions, because it is sufficiently close to a power of two (2¹⁴ = 16384). On such architectures (Cortex-M3/M4/M7, RISC-V rv32, x86, x86-64, ARM64/AARCH64), using

`uint32_t` as the combined type, enforcing wrapping after operations that modify the full turns part via

*combined* %= 1073479680; (1073479680 = 16380·65536) generates just one multiplication, some bit shifts, and a couple of additions and subtractions.