But the sign of the output of the subtraction must be such that it will, including when subtracting across the wrap point, give a clear indication of whether Angle1 or Angle2 is "bigger". Bigger not meaning here an actual size, but rather working n the way that for a 0 to 360 circle you might say 30 is "bigger" than 350 because you go upward from 350 to reach 30 by the shorter route.
IanB suggested "clockwise" and "counterclockwise", but I prefer "positive" and "negative".
AngleTo - AngleFrom should be positive if you need fewer iterations of incrementing AngleFrom than decrementing to get to Angle To.
AngleTo - AngleFrom should be negative if you need fewer iterations of decrementing AngleFrom than incrementing to get to Angle To.
AngleTo - AngleFrom should be zero if the two are equal.
The same logic is used in e.g. C
qsort():
compar(a, b) needs to return negative if
a<b, 0 if
a==b, and positive if
a>b.
I've got this to work easily where binary numbers are used as the limit, because subtracting them works across the limit of, for example, a uint8_t's wrap point, then going back to zero. But I'm a bit more confused when using numbers with an arbitrary wrap point, and where that wrap point goes between +MaxRevs and -MaxRevs (or +Maxrevs and -Maxrevs+1 I think more accurately, so that -MaxRevs and +MaxRevs are not duplicate values for the same point*).
Standard representable range of values is
-MaxRevs ..
+MaxRevs-1, i.e. including
-MaxRevs but excluding
+MaxRevs, based on two's complement integer range.
Let
RevsRange = 2*MaxRevs (
== (MaxRevs) - (-MaxRevs)), and must be representable in the type you use for
revs. Then:
while (revs >= MaxRevs) revs -= RevsRange; while (revs < -MaxRevs) revs += RevsRange;For an arbitrary value
revs, that might be many times
MaxRevs, you can use
revs -= RevsRange * (revs / RevsRange); if (revs >= MaxRevs) revs -= RevsRange; if (revs < -MaxRevs) revs += RevsRange;or, equivalently, giving the compiler more opportunities for optimization,
revs %= RevsRange; // Result is between -RevsRange+1 and RevsRange-1, inclusive if (revs >= MaxRevs) revs -= RevsRange; if (revs < -MaxRevs) revs += RevsRange;On architectures where conditionals are slow, multiplication/modulo is fast, but the compiler cannot eliminate them for above, you can use
revs = (revs + MaxRevs) % RevsRange; revs += (revs < 0) ? MaxRevs : -MaxRevs;which the compiler should know how to optimize. After the first line,
revs can be
-RevsRange+1..
RevsRange-1, but we will need to substract
MaxRevs to compensate for the initial addition. On the second line, if
revs < 0, we need to add
RevsRange - MaxRevs = MaxRevs; if
revs >= 0, we only need to subtract
MaxRev.
For arbitrary
NegRevs..PosRevs-1 range,
NegRevs < 0,
PosRevs > 0,
RevsRange = PosRevs - NegRevs, you can use
revs = (revs - NegRevs) % RevsRange; revs += (revs < 0) ? -NegRevs : NegRevs;while(count > MaxRevs){
count=count-2*MaxRevs;
}
while(count <= -MaxRevs){
count=count+2*MaxRevs;
}
Yes, that will limit
count to range
-MaxRevs+1 .. MaxRevs. The limit with the "or equal" check will be excluded. If both have the "or equal" check, then the later one dominates.
I do recommend you use
-MaxRevs..MaxRevs-1, instead, so your limits match the "standard" ones, e.g. two's complement behaviour (and thus
intN_t types' wrapping rules).