Czy słusznie mogę powiedzieć, że różnica między liczbą całkowitą ze znakiem i bez znaku jest następująca:
- Unsigned może zawierać większą wartość dodatnią i brak wartości ujemnej.
- Unsigned używa bitu wiodącego jako części wartości, podczas gdy wersja podpisana używa bitu najbardziej w lewo, aby określić, czy liczba jest dodatnia czy ujemna.
- liczby całkowite ze znakiem mogą zawierać liczby dodatnie i ujemne.
Jakieś inne różnice?
language-agnostic
integer
unsigned
signed
Shimmy Weitzhandler
źródło
źródło
Odpowiedzi:
Tak.
Istnieją różne sposoby reprezentowania podpisanych liczb całkowitych. Najłatwiejszym do zwizualizowania jest użycie lewego skrajnego bitu jako flagi ( znak i wielkość ), ale bardziej powszechne jest uzupełnienie dwóch . Oba są używane w większości współczesnych mikroprocesorów - zmiennoprzecinkowe używa znaku i wielkości, podczas gdy arytmetyka liczb całkowitych wykorzystuje uzupełnienie do dwóch.
tak
źródło
Przejdę do różnic na poziomie sprzętowym na x86. Jest to w większości nieistotne, chyba że piszesz kompilator lub używasz języka asemblera. Ale miło to wiedzieć.
Po pierwsze, x86 ma natywne wsparcie dla reprezentacji uzupełnienia dwóch liczb podpisanych. Możesz użyć innych reprezentacji, ale wymagałoby to więcej instrukcji i generalnie marnowałoby czas procesora.
Co rozumiem przez „wsparcie rodzime”? Zasadniczo mam na myśli, że istnieje zestaw instrukcji, których używasz dla liczb niepodpisanych i inny zestaw, którego używasz dla liczb podpisanych. Numery niepodpisane mogą znajdować się w tych samych rejestrach, co numery podpisane, i rzeczywiście można łączyć instrukcje podpisane i niepodpisane bez martwienia się o procesor. Do kompilatora (lub programisty asemblera) należy śledzenie, czy numer jest podpisany, czy nie, i stosowanie odpowiednich instrukcji.
Po pierwsze, liczby uzupełniające dwóch mają tę właściwość, że dodawanie i odejmowanie jest takie samo jak w przypadku liczb niepodpisanych. Nie ma znaczenia, czy liczby są dodatnie czy ujemne. (Więc idź naprzód,
ADD
aSUB
twoje liczby bez obaw.)Różnice zaczynają się ujawniać, jeśli chodzi o porównania. x86 ma prosty sposób ich rozróżnienia: powyżej / poniżej wskazuje porównanie bez znaku i większe / mniejsze niż wskazuje porównanie z podpisem. (Np.
JAE
Oznacza „Skacz, jeśli jest wyżej lub równo” i jest niepodpisany.)Istnieją również dwa zestawy instrukcji mnożenia i dzielenia, które dotyczą liczb całkowitych ze znakiem i bez znaku.
Na koniec: jeśli chcesz sprawdzić, powiedzmy, przepełnienie, zrobiłbyś to inaczej dla numerów podpisanych i niepodpisanych.
źródło
Zapytał tylko o podpisane i niepodpisane. Nie wiem, dlaczego ludzie dodają do tego dodatkowe rzeczy. Pozwól, że powiem ci odpowiedź.
Bez znaku: składa się tylko z wartości nieujemnych, tj. Od 0 do 255.
Podpisano: składa się zarówno z wartości ujemnych, jak i dodatnich, ale w różnych formatach, takich jak
To wyjaśnienie dotyczy 8-bitowego systemu liczbowego.
źródło
Tylko kilka punktów za kompletność:
ta odpowiedź dotyczy tylko reprezentacji liczb całkowitych. Mogą być inne odpowiedzi na zmiennoprzecinkowe;
reprezentacja liczby ujemnej może się różnić. Najczęstszym (jak dotąd - dziś jest prawie uniwersalny) w użyciu jest obecnie uzupełnienie dwóch . Inne reprezentacje obejmują uzupełnienie (dość rzadkie) i oznaczoną wielkość (znikająco rzadkie - prawdopodobnie używane tylko w muzeach), która po prostu wykorzystuje wysoki bit jako wskaźnik znaku, a pozostałe bity reprezentują bezwzględną wartość liczby.
Podczas korzystania z uzupełnienia do dwóch zmienna może reprezentować większy zakres (o jeden) liczb ujemnych niż liczb dodatnich. Jest tak, ponieważ zero jest uwzględniane w liczbach „dodatnich” (ponieważ bit znaku nie jest ustawiony na zero), ale nie są liczbami ujemnymi. Oznacza to, że nie można przedstawić wartości bezwzględnej najmniejszej liczby ujemnej.
kiedy używasz swojego uzupełnienia lub wielkości ze znakiem, możesz mieć zero reprezentowane jako liczbę dodatnią lub ujemną (co jest jednym z kilku powodów, dla których te reprezentacje nie są zwykle używane).
źródło
Zgodnie z tym, czego nauczyliśmy się w klasie, liczby całkowite ze znakiem mogą reprezentować zarówno liczby dodatnie, jak i ujemne, podczas gdy liczby całkowite bez znaku są tylko nieujemne.
Na przykład patrząc na liczbę 8-bitową :
niepodpisane wartości
0
do255
podpisane wartości mieszczą się w zakresie od
-128
do127
źródło
Wszystko oprócz punktu 2 jest poprawne. Istnieje wiele różnych oznaczeń dla podpisanych int, niektóre implementacje używają pierwszego, inne używają ostatniego, a jeszcze inne używają czegoś zupełnie innego. Wszystko zależy od platformy, z którą pracujesz.
źródło
Kolejną różnicą jest konwersja liczb całkowitych o różnych rozmiarach.
Na przykład, jeśli wyodrębniasz liczbę całkowitą ze strumienia bajtów (dla uproszczenia powiedzmy 16 bitów), z wartościami bez znaku, możesz:
(prawdopodobnie powinien rzucić 2 nd bajt, ale zgaduję kompilator zrobi dobry uczynek)
W przypadku podpisanych wartości należy się martwić o rozszerzenie znaku i wykonać:
źródło
Ogólnie rzecz biorąc, jest to poprawne. Nie wiedząc nic więcej o tym, dlaczego szukasz różnic, nie mogę wymyślić żadnych innych różnic między podpisanym a niepodpisanym.
źródło
Oprócz tego, co powiedzieli inni, w C nie można przepełnić liczby całkowitej bez znaku; zachowanie jest zdefiniowane jako arytmetyka modułu. Możesz przepełnić podpisaną liczbę całkowitą i teoretycznie (choć nie w praktyce w obecnych systemach głównego nurtu) przepełnienie może spowodować błąd (być może podobny do błędu dzielenia przez zero).
źródło
źródło
(w odpowiedzi na drugie pytanie) Używając tylko bitu znakowego (a nie uzupełnienia 2), możesz otrzymać -0. Niezbyt ładna.
źródło
Liczby całkowite ze znakiem w C reprezentują liczby. Jeśli
a
ib
są zmiennymi typów całkowitych ze znakiem, standard nigdy nie będzie wymagał od kompilatora przekształcenia wyrażeniaa+=b
wa
nic innego niż sumę arytmetyczną ich odpowiednich wartości. Oczywiście, jeśli suma arytmetyczna nie byłaby dopasowanaa
, procesor może nie być w stanie jej tam umieścić, ale standard nie wymagałby od kompilatora obcinania lub zawijania wartości, ani robienia czegokolwiek innego w tym zakresie, jeśli wartości przekraczające limity dla ich typów. Należy zauważyć, że chociaż standard tego nie wymaga, implementacje języka C mogą przechwytywać przepełnienia arytmetyczne o podpisanych wartościach.Niespisane liczby całkowite w C zachowują się jak abstrakcyjne algebraiczne pierścienie liczb całkowitych, które są zgodne z pewną potęgą dwóch, z wyjątkiem scenariuszy obejmujących konwersje na większe typy lub operacje z nimi. Konwersja liczby całkowitej o dowolnym rozmiarze na 32-bitowy typ bez znaku da element członkowski odpowiadający rzeczom, które są zgodne z tym modem całkowitym 4,294,967,296. Powodem odjęcia 3 od 2 daje 4 294 967 295, że dodanie czegoś zgodnego do 3 do czegoś zgodnego do 4 294 967 295 da coś zgodnego do 2.
Abstrakcyjne typy pierścieni algebraicznych to często przydatne rzeczy; niestety C używa sygnatury jako decydującego czynnika decydującego o tym, czy typ powinien zachowywać się jak pierścień. Co gorsza, niepodpisane wartości są traktowane jako liczby, a nie pierścieniowe elementy, gdy są konwertowane na większe typy, a niepodpisane wartości mniejsze niż
int
są konwertowane na liczby, gdy wykonywana jest na nich jakaś arytmetyka. Jeśliv
jestuint32_t
równy4,294,967,294
, tov*=v;
powinien zrobićv=4
. Niestety, jeśliint
ma 64 bity, nie wiadomo, cov*=v;
można zrobić.Biorąc pod uwagę obecny standard, sugerowałbym używanie typów niepodpisanych w sytuacjach, w których chce się zachowania związanego z pierścieniami algebraicznymi, a typów podpisanych, gdy chcemy reprezentować liczby. Szkoda, że C narysował rozróżnienia w ten sposób, ale są tacy, jacy są.
źródło
Niezapisane liczby całkowite są znacznie bardziej prawdopodobne, że złapią Cię w określonej pułapce niż liczby całkowite ze znakiem. Pułapka wynika z faktu, że chociaż powyższe 1 i 3 są poprawne, obu typom liczb całkowitych można przypisać wartość poza granicami tego, co może „zatrzymać” i zostanie ona po cichu przeliczona.
Po uruchomieniu tego otrzymasz następujące dane wyjściowe, mimo że obie wartości zostały przypisane do -1 i zadeklarowane inaczej.
źródło
Jedyną gwarantowaną różnicą między wartością ze znakiem i bez znaku w C jest to, że wartość ze znakiem może być ujemna, 0 lub dodatnia, podczas gdy bez znaku może być tylko 0 lub dodatnia. Problem polega na tym, że C nie definiuje formatu typów (więc nie wiesz, że twoje liczby całkowite są w uzupełnieniu do dwóch). Ściśle mówiąc, pierwsze dwa wymienione przez ciebie punkty są nieprawidłowe.
źródło
Musisz używać liczb całkowitych bez znaku podczas programowania w systemach wbudowanych. W pętlach, gdy nie ma potrzeby stosowania liczb całkowitych ze znakiem, użycie liczb całkowitych bez znaku pozwoli zaoszczędzić bezpieczeństwo niezbędne do zaprojektowania takich systemów.
źródło