C#
ma decimal
typ używany dla liczb, które wymagają dokładnej reprezentacji w bazie 10. Na przykład, 0.1
nie może być reprezentowany w bazie 2 (np. float
i double
) i zawsze będzie przybliżeniem, gdy jest przechowywany w zmiennych tego typu.
Zastanawiałem się, czy odwrócony fakt był również możliwy. Czy istnieją liczby, które nie są reprezentowalne w bazie 10, ale mogą być reprezentowane w bazie 2 (w którym to przypadku chciałbym użyć float
zamiast decimal
nich do obsługi)?
0.11_b2
, zapisz ją jako0.5 + 0.5 * 0.5
. Czy istnieje krok, który może się nie powieść lub spowodować powtarzanie dziesiętne? Osobiście uważam, że ćwiczenie to wykonuje świetną robotę, jeśli chodzi o intuicję dotyczącą liczb podstawowych 2. Podejrzewam, że można pójść o krok dalej i zamienić to ćwiczenie w dowód budowlany.0.0999999....998..
dokładnie, ale nie pełną liczbę0.1
- przybliżenia, takie jak zaokrąglanie do najbliższej setki,0.100
stanowią problem z implementacją, który polega na tym, aby nie pokazywać wszystkich cyfr i zaokrąglać je.Odpowiedzi:
Oto klucz do twojego rozterki:
10
jest produktem2
i5
. Można reprezentować dowolną liczbę dokładnie w bazie 10 dziesiętne to k * 1/2 n * 1/5 m , gdziek
,n
im
są liczbami całkowitymi.Alternatywnie - jeśli liczba
n
w 1 / n zawiera czynnik, który nie jest częścią czynników podstawy, liczby nie będzie można przedstawić dokładnie w stałej liczbie cyfr w systemie binarnym / dziesiętnym / jakimkolwiek rozszerzeniu tego liczba - będzie miała część powtarzalną. Na przykład 1/15 = 0,0666666666 .... ponieważ 3 (15 = 3 * 5) nie jest współczynnikiem 10.Zatem wszystko, co można dokładnie przedstawić w podstawie 2 (k * 1/2 n ), może być dokładnie przedstawione w podstawie 10.
Poza tym istnieje kwestia liczby cyfr / bitów używanych do przedstawienia liczby. Istnieje kilka liczb, które można dokładnie przedstawić w jakiejś bazie, ale zajmuje to więcej niż pewną liczbę cyfr / bitów.
W systemie dwójkowym liczba 1/10, która dogodnie wynosi 0,1 w systemie dziesiętnym, nie może być reprezentowana jako liczba, która może być reprezentowana przez stałą liczbę bitów w systemie dwójkowym. Zamiast tego jest to 0,00011001100110011 ... 2 (z częścią 0011 powtarzającą się na zawsze).
Spójrzmy na numer 1 2 /1010 2 nieco bliżej.
Jest to dokładnie ten sam rodzaj rzeczy, który dostajesz, gdy próbujesz wykonać długi podział na 1/3.
1/10, gdy uwzględniono 1 / (2 1 * 5 1 ). W przypadku podstawy 10 (lub dowolnej wielokrotności 10) liczba ta kończy się i jest znana jako liczba zwykła . Rozwinięcie dziesiętne, które się powtarza, znane jest jako powtarzanie dziesiętne , a liczby, które trwają wiecznie bez powtarzania, są liczbami niewymiernymi.
Matematyki za tego zagłębia się małe twierdzenie Fermata ... i po uruchomieniu mówiąc Fermat lub twierdzenie, staje się pytanie Math.SE .
Odpowiedź brzmi nie'.
Zatem w tym miejscu wszyscy powinniśmy wyjaśnić, że każde rozwinięcie binarne o stałej długości liczby wymiernej może być reprezentowane jako rozwinięcie dziesiętne o stałej długości.
Pozwala zapoznać się bliżej po przecinku w C # , który prowadzi nas do dziesiętny zmiennoprzecinkowych w .NET i danego autora, to zgadzam się, że to jak to działa.
Od razu zaznaczę, że z powodu tej implementacji istnieją liczby w
double
typie, w których nie można reprezentowaćdecimal
- te, które są poza zakresem.Double.Epsilon
jest to,4.94065645841247e-324
co nie może być reprezentowane wdecimal
, ale może wdouble
.Jednak w zakresie, który może reprezentować dziesiętny, ma więcej bitów dokładności niż w przypadku innych rodzimych typów i może reprezentować je bez błędów.
Istnieje kilka innych typów. W języku C # istnieje BigInteger, która może reprezentować dowolnie dużą liczbę całkowitą. Nie ma odpowiednik Java BigDecimal (który może reprezentować liczby z cyfr dziesiętnych do wysokości 2 32 cyfr - co jest sporym zasięgu) dokładnie . Jeśli jednak trochę się przekręcisz, możesz znaleźć ręcznie wdrażane implementacje.
Istnieje kilka języków, które mają również racjonalny typ danych, który pozwala dokładnie reprezentować racjonalne (tak, że 1/3 to w rzeczywistości 1/3).
Specjalnie dla C # i wyboru liczby zmiennoprzecinkowej lub wymiernej, odłożę się do Jona Skeeta z pływającego kufla dziesiętnego w .NET :
źródło
n = 15
ib = 10
nie są względnie pierwsze („nie dzielą żadnych wspólnych pozytywnych czynników (dzielników) z wyjątkiem 1”), ponieważ dzielą 5 jako czynnik. Kluczem jest to, że nie wszystkie czynniki 15 (5 i 3) nie są również czynnikami 10. (Poza tym: czy istnieje słowo wskazujące liczby, które dzielą lub nie dzielą wszystkich wspólnych czynników?) Myślę, że jest to zgrabnie Owinięte w twojek, n, m
równanie, ale żeby naprawdę owinąć wokół niego głowę, musiałbym zobaczyć trójwymiarową fabułę. Niezależnie od tego, zasłużony +1 dla ciebie.Gdy znajdziesz się poza zakresem dopuszczalnych wartości, odpowiedź brzmi tak. To powiedziawszy, prawie wszystko w zakresie będzie miało reprezentację. C # Odniesienie dziesiętne Chociaż nie podano tego w specyfikacji, liczb niewymiernych nie można dokładnie przedstawić (np. E 1 , pi, pierwiastek kwadratowy z 2 itd.).
1 Podziękowania dla MichaelT za przypomnienie mi innej irracjonalnej liczby.
źródło
e
(2,71 ...). Log naturalny - ln (x) jest podstawą logu e. Zatem irracjonalne podstawy istnieją i są użyteczne. Szczególnej użyteczności base pi, nie jestem pewien - ale to nie znaczy, że gdzieś jej nie używa.Typ zmiennoprzecinkowy typu base-two byłby w stanie precyzyjnie przedstawić wiele wartości, których typ typu dziesiętnego o tym samym rozmiarze nie mógłby. Każda wartość, która byłaby dokładnie reprezentowana przez typ podstawy 2 o pewnym rozmiarze, byłaby dokładnie reprezentowana w typie podstawy 10 o wystarczającej wielkości. Wymagany rozmiar dla typu czysto dziesiętnego do reprezentowania wszystkich wartości binarnej liczby zmiennoprzecinkowej zależałby od zakresu wykładniczego typu binarnego; setki bitów za
float
, lub tysiące zadouble
.To powiedziawszy,
Decimal
typ jest na tyle duży, że można by go uczynić użytecznym jako typ „uniwersalny” zdolny do zachowania wartości dowolnego innego liczbowego prymitywu i dostarczenia innych dodatkowych funkcji oprócz (jeśli nic więcej, użyj jednego bitu aby wskazać, czy zapamiętana wartość jest wynikiem konwersji adouble
, a jeśli ten bit jest ustawiony, należy użyć 64 bitów do przechowywania danej wartości). Microsoft jednak tego nie zrobił. W rezultacie, konwersjadouble
doDecimal
całkowicie nie do dużych wartości powoduje małe wartości zaokrągla do najbliższej 1E-28. Ponadto, nawet w zakresie dynamicznymdecimal
, metoda konwersji nie będzie „w obie strony”. Na przykład ocena 1,0 / 3,0 jako podwójna da 0,33333333333333333148, ale konwersja na dziesiętną da 0,3333333333333333m, a konwersja z powrotem na podwójną da 0,33333333333333329818.źródło