Mając czysto matematyczne doświadczenie, jest to nieco bardziej matematyczne podejście dla wszystkich zainteresowanych.
Jeśli zaczniemy od 8-bitowej liczby całkowitej ze znakiem i bez znaku, mamy w zasadzie liczbę całkowitą modulo 256, jeśli chodzi o dodawanie i mnożenie, pod warunkiem, że dopełnienie 2 jest używane do reprezentowania liczb całkowitych ujemnych (i tak robi to każdy nowoczesny procesor) .
Rzeczy różnią się w dwóch miejscach: jedno to operacje porównania. W pewnym sensie liczby całkowite modulo 256 są najlepiej uważane za koło liczb (podobnie jak liczby całkowite modulo 12 na staromodnej analogowej powierzchni zegarowej). Aby porównania numeryczne (czyli x <y) były znaczące, musieliśmy zdecydować, które liczby są mniejsze niż inne. Z punktu widzenia matematyka chcemy jakoś osadzić liczby całkowite modulo 256 w zbiorze wszystkich liczb całkowitych. Odwzorowanie 8-bitowej liczby całkowitej, której binarna reprezentacja składa się z samych zer, na liczbę całkowitą 0, jest oczywistą czynnością. Następnie możemy przystąpić do mapowania innych, tak aby „0 + 1” (wynik zerowania rejestru, powiedzmy ax, i zwiększenie go o jeden, poprzez „inc ax”) trafił do liczby całkowitej 1 i tak dalej. Możemy zrobić to samo z -1, na przykład mapując „0-1” na liczbę całkowitą -1 i „0-1-1” do liczby całkowitej -2. Musimy upewnić się, że to osadzanie jest funkcją, więc nie można zmapować pojedynczej liczby całkowitej 8-bitowej na dwie liczby całkowite. Oznacza to, że jeśli zamapujemy wszystkie liczby na zbiór liczb całkowitych, będzie tam 0, wraz z niektórymi liczbami całkowitymi mniejszymi niż 0 i niektórymi większymi niż 0. Istnieją zasadniczo 255 sposobów, aby to zrobić za pomocą 8-bitowej liczby całkowitej (zgodnie z do jakiego minimum chcesz, od 0 do -255). Następnie możesz zdefiniować „x <y” w kategoriach „0 <y - x”.
Istnieją dwa typowe przypadki użycia, dla których uzasadnione jest wsparcie sprzętowe: jeden przy wszystkich niezerowych liczbach całkowitych większych od 0, a drugi przy około 50/50 podzielonych wokół 0. Wszystkie inne możliwości można łatwo emulować poprzez translację liczb za pomocą dodatkowego „add” i sub 'przed operacjami, a potrzeba tego jest tak rzadka, że nie mogę wymyślić wyraźnego przykładu we współczesnym oprogramowaniu (ponieważ możesz po prostu pracować z większą mantysą, powiedzmy 16 bitów).
Innym problemem jest odwzorowanie 8-bitowej liczby całkowitej na przestrzeń 16-bitowych liczb całkowitych. Czy -1 idzie do -1? Tego właśnie chcesz, jeśli 0xFF ma reprezentować -1. W takim przypadku rozsądne jest wydłużanie znaków, aby 0xFF poszedł do 0xFFFF. Z drugiej strony, jeśli 0xFF miało reprezentować 255, to chcesz, aby było odwzorowane na 255, a więc na 0x00FF, a nie 0xFFFF.
Jest to również różnica między operacjami „przesunięcia” i „przesunięcia arytmetycznego”.
Ostatecznie jednak sprowadza się to do tego, że int w oprogramowaniu nie są liczbami całkowitymi, ale reprezentacjami w postaci binarnej i tylko niektóre z nich mogą być reprezentowane. Projektując sprzęt, należy dokonać wyboru, co zrobić natywnie w sprzęcie. Ponieważ w przypadku uzupełnienia 2 operacje dodawania i mnożenia są identyczne, sensowne jest przedstawianie w ten sposób ujemnych liczb całkowitych. Zatem jest to tylko kwestia operacji, które zależą od liczb całkowitych, które mają reprezentować twoje reprezentacje binarne.