Jestem zdezorientowany, dlaczego dbamy o różne reprezentacje dla dodatniego i ujemnego zera.
Z niejasnych wspomnień czytam, że posiadanie ujemnej reprezentacji zera jest niezwykle ważne w programowaniu, które obejmuje liczby zespolone. Nigdy nie miałem okazji pisać kodu zawierającego liczby zespolone, więc jestem nieco zaskoczony, dlaczego tak się dzieje.
Artykuł Wikipedii na temat tego pojęcia nie jest szczególnie pomocny; tylko niejasne twierdzenia o podpisanym zeru upraszczają niektóre operacje matematyczne w liczbach zmiennoprzecinkowych, jeśli dobrze rozumiem. W tej odpowiedzi wymieniono kilka funkcji, które zachowują się inaczej. Być może z przykładów można wywnioskować, jeśli znasz sposoby ich użycia. (Chociaż szczególny przykład złożonych pierwiastków kwadratowych wydaje się zupełnie niewłaściwy, ponieważ te dwie liczby są matematycznie równoważne, chyba że mam nieporozumienie.) Ale nie byłem w stanie znaleźć jasnego stwierdzenia o rodzaju kłopotów, które można spotkać, gdyby ich nie było. Im więcej zasobów matematycznych udało mi się znaleźć, stwierdziłem, że nie ma między nimi rozróżnienia z matematycznego punktu widzenia, a artykuł z Wikipedii wydaje się sugerować, że rzadko jest to postrzegane poza obliczeniami, poza opisywaniem ograniczeń.
Dlaczego więc zero ujemne jest cenne w informatyce? Jestem pewien, że coś mi umknęło.
źródło
sqrt(-1+0i) = i
isqrt(-1-0i) = -i
, choć uważam, że ma odpowiednią składnię dla jakiegoś języka programowania. Będę edytować, aby być bardziej przejrzystym.Odpowiedzi:
Należy pamiętać, że w arytmetyce FPU 0 niekoniecznie musi oznaczać dokładnie zero, ale także wartość zbyt małą, aby można ją było przedstawić za pomocą danego typu danych, np.
a jest zbyt małe, aby mogło być poprawnie reprezentowane przez zmiennoprzecinkowe (32 bity), więc jest „zaokrąglone” do -0.
Powiedzmy, że nasze obliczenia są kontynuowane:
Ponieważ a jest zmiennoprzecinkowe, spowoduje to nieskończoność, która jest daleka od poprawnej odpowiedzi -1000000000000000000.0
Teraz obliczmy b, jeśli nie ma -0 (więc zaokrąglono do +0):
Wynik jest znowu błędny z powodu zaokrąglenia, ale teraz jest „bardziej zły” - nie tylko liczbowo, ale co ważniejsze z powodu innego znaku (wynikiem obliczenia jest + nieskończoność, poprawny wynik to -1000000000000000000.0).
Nadal można powiedzieć, że to nie ma znaczenia, ponieważ oba są w błędzie. Ważne jest to, że istnieje wiele aplikacji numerycznych, w których najważniejszym wynikiem obliczeń jest znak - np. Przy podejmowaniu decyzji o skręceniu w lewo lub w prawo na skrzyżowaniu za pomocą algorytmu uczenia maszynowego można zinterpretować wartość dodatnią => skręt w lewo, wartość ujemna => skręć w prawo, rzeczywista „wielkość” wartości jest po prostu „współczynnikiem ufności”.
źródło
+inf
oraz-inf
podczas normalnej pracy są uszkodzone.+inf
i-inf
. Jeśli twój program powoduje niedopasowanie zmiennoprzecinkowe, to jest to błąd, a to, co dzieje się później, nie jest tak interesujące, imho. Wciąż brakuje nam praktycznych przykładów, w których przydatna jest wartość -0.Po pierwsze, jak utworzyć -0? Istnieją dwa sposoby: (1) wykonaj operację zmiennoprzecinkową, w której wynik matematyczny jest ujemny, ale tak blisko zera, że zostaje zaokrąglony do zera, a nie do liczby niezerowej. To obliczenie da -0. (b) Niektóre operacje z zerami: Pomnóż dodatnie zero przez liczbę ujemną lub podziel dodatnie zero przez liczbę ujemną lub neguj dodatnie zero.
Posiadanie ujemnego zera nieco upraszcza mnożenie i dzielenie, znak x * y lub x / y jest zawsze znakiem x, wyłącznym lub znakiem y. Bez ujemnego zera konieczne byłoby dodatkowe sprawdzenie, aby zastąpić -0 +0.
Jest kilka bardzo rzadkich sytuacji, w których jest to przydatne. Możesz sprawdzić, czy wynik pomnożenia lub dzielenia jest matematycznie większy lub mniejszy od zera, nawet jeśli występuje niedopełnienie (o ile wiesz, że wynik nie jest matematycznym zerem). Nie pamiętam, żeby kiedykolwiek napisałem kod, który ma znaczenie.
Optymalizacja kompilatorów nienawidzi -0. Na przykład nie można zastąpić x + 0,0 x, ponieważ wynik nie powinien być x, jeśli x wynosi -0,0. Nie można zamienić x * 0,0 na 0,0, ponieważ wynik powinien wynosić -0,0, jeśli x <0 lub x wynosi -0,0.
źródło
-5
i5
wchodzącfmod()
. To dość denerwujące dla mojego przypadku użycia.C # Double, który jest zgodny z IEEE 754
drukuje:
właściwie to trochę wyjaśnić ...
Oznacza to coś znacznie bliższego d =
The Limit of x as x approaches 0-
lubThe Limit of x as x approaches 0 from the negatives
.Aby odpowiedzieć na komentarz Filipa ...
Zasadniczo zero ujemne oznacza niedopełnienie.
Praktyczne zastosowanie ujemnego zera, jeśli w ogóle, jest bardzo mało praktyczne ...
na przykład ten kod (ponownie C #):
daje ten wynik:
Aby wyjaśnić nieformalnie, wszystkie wartości specjalne, które może mieć zmiennoprzecinkowy IEEE 754 (dodatnia nieskończoność, ujemna nieskończoność, NAN, -0,0) nie mają znaczenia w sensie praktycznym. Nie mogą reprezentować żadnej wartości fizycznej ani żadnej wartości, która ma sens w obliczeniach „rzeczywistego świata”. Chodzi im zasadniczo o to:
sqrt(-7)
, lub nie ma limitu podobnego0/0
lub podobnegoPositiveInfinity/PositiveInfinity
źródło
Pytanie o to, w jaki sposób odnosi się to do obliczeń liczb zespolonych, naprawdę stanowi sedno tego, dlaczego zarówno +0, jak i -0 istnieją w zmiennoprzecinkowym. Jeśli w ogóle studiujesz analizę złożoną, szybko odkrywasz, że funkcji ciągłych od złożonych do złożonych zwykle nie można traktować jako „pojedynczej wartości”, chyba że przyjmie się „uprzejmą fikcję”, że dane wyjściowe tworzą tak zwaną „powierzchnię Riemanna”. Na przykład logarytm złożony przypisuje każdemu wejściowi nieskończenie wiele wyników; kiedy „łączysz je” w celu uzyskania ciągłego wyniku, wszystkie części rzeczywiste tworzą „nieskończoną powierzchnię korkociągu” wokół źródła. Ciągła krzywa, która przecina rzeczywistą oś „w dół od strony urojonej pozytywnie” i kolejna krzywa, która „owija się wokół bieguna” i przecina rzeczywistą oś ”
Teraz zastosuj to do programu numerycznego, który oblicza za pomocą złożonego zmiennoprzecinkowego. Działanie podjęte po danym obliczeniu może się bardzo różnić w zależności od tego, który „arkusz” jest obecnie „włączony”, a znak ostatniego obliczonego wyniku prawdopodobnie mówi, który „arkusz”. Załóżmy teraz, że wynik był zerowy? Pamiętaj, że „zero” naprawdę oznacza „zbyt małe, aby poprawnie reprezentować”. Ale jeśli obliczenia mogłyby zapewnić -zachowanie znaku- (tj. Zapamiętanie, który „arkusz”), gdy wynik wynosi zero, kod może sprawdzić znak i wykonać właściwą akcję nawet w tej sytuacji.
źródło
Powód jest prostszy niż zwykle
Oczywiście jest wiele hacków, które wyglądają naprawdę ładnie i są użyteczne (jak zaokrąglanie do
-0.0
lub,+0.0
ale załóżmy, że mamy reprezentację podpisanej int ze znakiem minus / plus na początku (wiem, że jest to rozwiązane przez kod binarny U2) w liczbach całkowitych zwykle, ale przyjmują mniej złożoną reprezentację podwójnej):Co jeśli jest liczba ujemna?
Okej, to proste. Więc reprezentujemy 0:
To też w porządku. Ale co z tym
1 000
? Czy to musi być zakazany numer? Lepiej nie.Załóżmy więc, że istnieją dwa typy zera:
To uprości nasze obliczenia i na szczęście zapewni dodatkowe zaokrąglenie. Więc
+0
i-0
pochodzą tylko z kwestii reprezentacji binarnej.źródło