Jak działa porównanie liczb całkowitych wewnętrznie?

18

Np. Przy porównywaniu dwóch liczb całkowitych w następujący sposób w języku C:

if (3 > 2) {
    // do something
}

Jak wewnętrznie ocenia się, czy 3 jest większe niż 2 (prawda) czy nie (fałsz)?

Niek
źródło
19
Obecna odpowiedź jest odpowiednia w przypadku, gdy porównanie dotyczy wyrażenia zmiennego, ale brakuje wyłączenia, że ​​wiele współczesnych kompilatorów spojrzy na twój fragment kodu, wykryje, że wyrażenie będzie zawsze prawdziwe (z powodu literałów) i po prostu ifcałkowicie zignoruje , przechodząc od razu do kodowania do something.
SJuan76,
3
Możliwy duplikat działania komputerów?
3
@Snowman Nie zgadzam się. Wszelkie zapytania programowe „jak to działa” można sprowadzić do tego pytania, ale to nie czyni ich duplikatami.
user1643723,
1
@ user1643723 Dzieje się tak, gdy dana funkcja jest określonym kodem operacyjnym.
Chrylis
1
@ user1643723 Pytanie dotyczy tego, jak komputer wykonuje podstawową operację, a najwyższa odpowiedź omawia bramki logiczne i tabele logiczne. Dwa tematy, które są szeroko omówione w głównej odpowiedzi dupe target, która również odpowiada na twoje pytanie.

Odpowiedzi:

61

Całą drogę do króliczej nory, co? OK, spróbuję.

Krok 1. Od C do języka maszynowego

Kompilator C przekształca twoje porównanie w kody operacyjne przechowywane w języku maszynowym . Język maszyny to ciąg liczb, które CPU interpretuje jako instrukcje. W tym przypadku byłyby dwa kody: „odejmij z przeniesieniem” i „skacz, jeśli przeniesiesz”. Innymi słowy, 2 odejmuje się od 3 w jednej instrukcji, a następna instrukcja sprawdza, czy się przepełniła. Poprzedziłyby je dwie instrukcje ładowania liczb 2 i 3 do miejsc, w których można je porównać.

MOV AX, 3    ; Store 3 in register AX
MOV BX, 2    ; Store 2 in register BX
SUB AX, BX   ; Subtract BX from AX
JC  Label    ; If the previous operation overflowed, continue processing at memory location "Label"

Każde z powyższych ma reprezentację binarną; na przykład kodem SUBjest 2Dhex lub 00101101binarnie.

Krok 2. Kody do ALU

Arytmetyczne opcodes podoba ADD, SUB, MUL, i DIVwykonać podstawowe matematyki całkowitą przy użyciu ALU lub jednostki arytmetyczno-logiczne wbudowany w CPU. Numery są przechowywane w rejestrach według niektórych kodów; inne kody polecają chipowi wezwać ALU do wykonania obliczeń matematycznych na czymkolwiek, co jest zapisane w rejestrach w tym czasie.

Uwaga: w tym momencie jesteśmy daleko od wszystkiego, o co martwiłby się każdy inżynier oprogramowania, pracując z 3GL jak C.

Krok 3. ALU, pół-sumator i pełny sumator

Czy wiesz, że wszystkie znane operacje matematyczne można sprowadzić do szeregu operacji NOR ? I tak właśnie działa ALU.

ALU wie tylko, jak pracować z liczbami binarnymi i może wykonywać tylko operacje logiczne, takie jak OR, NOT, AND i XOR. Implementacja binarnego dodawania i odejmowania realizowana jest za pomocą szeregu logicznych operacji ułożonych w określony sposób w podsystemie znanym jako sumator . Podsystemy te składają się z sieci „półdodujących”, które działają na dwóch bitach i określają ich sumę bitów oraz flagę przenoszenia bitów. Łącząc je w całość, ALU może wykonywać operacje na liczbach o 8, 16, 32 itd. Bitach.

Half-Adder

Co z odejmowaniem? Odejmowanie to kolejna forma dodawania:

A - B = A + (-B)

ALU oblicza -B, biorąc pod uwagę uzupełnienie dwóch B. Po przekonwertowaniu na wartość ujemną przesłanie wartości do sumatora spowoduje operację odejmowania.

Krok 4: Ostatni krok: tranzystory na chipie

Operacje sumatorów są realizowane za pomocą kombinacji komponentów elektrycznych, które oddziałują ze sobą, tworząc „bramki logiczne”, takie jak te znalezione w logice tranzystorowo-tranzystorowej lub TTL lub w CMOS . Kliknij tutaj, aby zobaczyć kilka przykładów, aby zobaczyć, jak są połączone.

Oczywiście na chipie te „obwody” są zaimplementowane w milionach maleńkich kawałków materiału przewodzącego i nieprzewodzącego, ale zasada jest taka sama, jakby były pełnowymiarowymi komponentami na płycie chlebowej. Obejrzyj ten film, który pokazuje wszystkie tranzystory na mikroczipie przez soczewkę mikroskopu elektronicznego.

Kilka dodatkowych uwag:

  1. Napisany kod byłby w rzeczywistości wstępnie obliczony przez kompilator i nie zostałby wykonany w czasie wykonywania, ponieważ składa się wyłącznie ze stałych.

  2. Niektóre kompilatory nie kompilują się do kodu maszynowego, ale wprowadzają jeszcze jedną warstwę, na przykład kod bajtowy Java lub język pośredni .NET. Ale ostatecznie wszystko jest wykonywane za pomocą języka maszynowego.

  3. Niektóre operacje matematyczne nie są w rzeczywistości obliczane; są one wyszukiwane w ogromnych tabelach na arytmetycznej jednostce koprocesowej lub zawierają kombinację wyszukiwania i obliczeń lub interpolacji. Przykładem może być funkcja obliczania pierwiastka kwadratowego . Współczesne procesory komputerowe mają zmiennoprzecinkowe jednostki przetwarzania w każdym rdzeniu procesora.

John Wu
źródło
3
FWIW, odnosząc się do TTL, może być mylące, ponieważ praktycznie żaden współczesny procesor nie używa sygnalizacji TTL, większość używa CMOS FET i niższych napięć zamiast 5 V BJT.
whatsisname
2
CMOS zdecydowanie byłby lepszym odniesieniem niż TTL, jak sugeruje @whatsisname, ponieważ nie tylko jest bardziej dokładny do tego, co dzieje się w nowoczesnych procesorach, ale jest również znacznie prostszy koncepcyjnie.
Jules
3
@JackAidley to właśnie oznacza ta część: „Innymi słowy, 2 jest odejmowane od 3 w jednej instrukcji, a następna instrukcja sprawdza, czy się przepełniła”.
KutuluMike,
1
Nitpicking: Przypuszczam, CMPże zostanie użyty, SUBale nie - ale z drugiej strony jest to mniej więcej „ SUBgdy wynik jest ignorowany i ustawiane są tylko flagi”
Hagen von Eitzen
5
Twoje definicje dodawania pół i pełnego sumowania są niepoprawne. Pół sumatora pobiera dwa 1-bitowe wejścia i zwraca sumę i przenosi. Pełny sumator pobiera dodatkowe wejście przeniesienia, ale wciąż jest tylko jednym bitem. Istnieje wiele sposobów tworzenia sumatora N-bitowego, najprostszym jest sumator z przenoszeniem tętnienia, który jest tylko łańcuchem N pełnych sumatorów. W praktyce dla większych Ns ma to dość duże opóźnienie, dlatego w nowoczesnych projektach CPU stosowane są bardziej złożone projekty.
Voo,