Quello che vuoi fare è l'aritmetica modulare.La macchina del complemento a 2 fa già questo con la matematica intera. Quindi, mappando i tuoi valori nell'aritmetica del complemento a 2, puoi ottenere l'operazione modolo libera.
Il trucco rappresenta l'angolo come una frazione di 360 gradi tra 0 e 1-epsilon. Certo, quindi i tuoi angoli costanti dovrebbero essere rappresentati allo stesso modo, ma ciò non dovrebbe essere difficile; è solo un po 'di matematica che possiamo nascondere in una funzione di conversione (er, macro).
Il valore in questa idea è che se si aggiungono o si sottraggono angoli, si otterrà un valore di cui si desidera la parte frazione e la cui parte intera si desidera eliminare. Se rappresentiamo la frazione come un numero a virgola fissa a 32 bit con il punto binario a 2^32 (ad esempio, a sinistra di quello che è normalmente considerato un bit di segno), qualsiasi overflow della frazione semplicemente cade dalla parte superiore del Valore a 32 bit gratis. Quindi, esegui tutto il calcolo matematico intero e la rimozione "overflow" avviene gratuitamente.
Così mi piacerebbe riscrivere il codice (conservando l'idea di gradi volte 10):
typedef unsigned int32 angle; // angle*3600/(2^32) represents degrees
#define angle_scale_factor 1193046.47111111 // = 2^32/3600
#define make_angle(degrees) (unsigned int32)((degrees%3600)*angle_scale_factor)
#define make_degrees(angle) (angle/(angle_scale_factor*10)) // produces float number
...
angle a = make_angle(100); // compiler presumably does compile-time math to compute 119304647
angle b = make_angle(200); // = 238609294
angle c = a - b; // compiler should generate integer subtract, which computes 4175662649
#if 0 // no need for this at all; other solutions execute real code to do something here
if (c < 0) // this can't happen
{ c += 3600; } // this is the wrong representation for our variant
#endif
// speed doesn't matter here, we're doing output:
printf("final angle %f4.2 = \n", make_degrees(c)); // should print 350.00
non ho compilato ed eseguire questo codice.
Le modifiche per rendere questi gradi volte 100 o volte 1 sono piuttosto facili; modificare il angle_scale_factor. Se si dispone di una macchina a 16 bit, passare a 16 bit è altrettanto semplice; se si dispone di 32 bit e si desidera eseguire solo la matematica a 16 bit, sarà necessario mascherare il valore da stampare a 16 bit.
Questa soluzione ha un'altra proprietà piacevole: hai documentato quali variabili sono gli angoli (e hanno rappresentazioni divertenti). Il codice originale di OP li ha semplicemente chiamati ints, ma non è quello che rappresentano; un futuro manutentore sarà sorpreso dal codice originale, specialmente se trova la sottrazione isolata dalle variabili.
Perché sei preoccupato per la filiale? L'alternativa è qualcosa come '((a - b) + 3600)% 3600'. Questo presuppone che 'a' e' b' siano nel range '0..3600' già; se non sono sotto controllo, la soluzione più generale è quella che Drew McGowen suggerisce: ((a - b)% 3600 + 3600)% 3600'. La perdita del ramo deve essere molto costosa per rendere utile quel calcolo. –
Un trucco che usavo sarebbe '((a - b)% 3600 + 3600)% 3600' - sebbene con due operatori modulo, in realtà potrebbe essere meglio usare solo il confronto –
@JonathanLeffler abbiamo un vecchio, cattivo , tutto tranne il compilatore ottimizzato. Sta generando rami gonfiati. Ho appena controllato entrambe le risposte, ognuna produce meno istruzioni di assemblaggio e un codice più semplice da mantenere. Se entrambi poteste fornirgli una risposta, potrei darvi una conferma e accettare quella di jonathan. Non ho bisogno di 2 ops di modulo. Entrambi i valori 'a' e' b' sono sotto il nostro controllo. –