Co chcesz zrobić to arytmetyka modułowa.Twój komputer z uzupełnieniem 2 już to robi z matematyką całkowitą. A zatem, mapując twoje wartości na arytmetyczne uzupełnienie 2, możesz uwolnić działanie modolo.
Podstęp przedstawia kąt jako ułamek 360 stopni między 0 a 1-epsilon. Oczywiście wtedy wasze stałe kąty musiałyby być reprezentowane podobnie, ale nie powinno to być trudne; to tylko odrobina matematyki, którą możemy ukryć w funkcji konwersji (er, makro).
Wartość tego pomysłu polega na tym, że jeśli dodasz lub odejmiesz kąty, otrzymasz wartość, której części ułamka chcesz i której część całkowita chcesz wyrzucić. Jeśli reprezentujemy frakcję jako 32-bitową stałą liczbę punktów z dwójkowym punktem na 2^32 (np. Na lewo od tego, co zwykle uważa się za bit znaku), wszelkie przepełnienia frakcji po prostu spadają z góry 32-bitowa wartość za darmo. Więc robisz wszystkie matematykę całkowitą, a usuwanie "przepełnienia" dzieje się za darmo.
Więc ja przepisać kod (konserwujący ideę stopni razy 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
Nie skompilowany i uruchomić tego kodu.
Zmiany, które sprawiają, że stopnie razy 100 lub 1 są dość łatwe; zmodyfikuj współczynnik angle_scale_factor. Jeśli masz maszynę 16-bitową, przełączanie na 16 bitów jest równie łatwe; jeśli masz 32 bity i nadal chcesz zrobić tylko 16-bitową matematykę, musisz zamaskować wartość do wydrukowania na 16 bitów.
To rozwiązanie ma jeszcze jedną fajną właściwość: udokumentowałeś, które zmienne są kątami (i mają zabawne reprezentacje). Pierwotny kod OP właśnie nazwał je ints, ale to nie jest to, co reprezentują; przyszły opiekun zostanie zaskoczony oryginalnym kodem, zwłaszcza jeśli znajdzie odejmowanie od zmiennych.
Dlaczego martwisz się o oddział? Alternatywą jest coś w stylu '((a - b) + 3600)% 3600'. Zakłada to, że 'a' i' b' są już w zakresie '0..3600'; jeśli nie są pod kontrolą, bardziej ogólne rozwiązanie to takie, które sugeruje Drew McGowen: ((a - b)% 3600 + 3600)% 3600'. Chybienie oddziału musi być bardzo kosztowne, aby ta kalkulacja była warta zachodu. –
Podstęp, którego używałem, to '((a - b)% 3600 + 3600)% 3600' - choć z dwoma operatorami modulus, w rzeczywistości może być lepiej, używając tylko porównania –
@ JonathanLeffler mamy starą, złą , wszystko oprócz zoptymalizowanego kompilatora. Generuje rozdęte gałęzie. Właśnie sprawdziłem obie odpowiedzi, z których każda produkuje mniej instrukcji montażu i łatwiejszego kodu do utrzymania. Jeśli oboje moglibyście udzielić tego jako odpowiedzi, mogę dać panu upominek i zaakceptować jonathan. Nie potrzebuję 2 modułów ops. Obie wartości "a" i "b" znajdują się pod naszą własną kontrolą. –