Przykład:
float timeRemaining = 0.58f;
Dlaczego f
na końcu tego numeru jest wymagana litera?
c#
floating-point
Tomasz
źródło
źródło
double
.double & int
.Odpowiedzi:
Twoja deklaracja pływaka składa się z dwóch części:
timeRemaining
jest typufloat
.0.58
tej zmiennej.Problem pojawia się w części 2.
Prawa strona jest oceniana samodzielnie. Zgodnie ze specyfikacją C # liczba zawierająca kropkę dziesiętną, która nie ma sufiksu, jest interpretowana jako
double
.Mamy więc teraz
double
wartość, którą chcemy przypisać zmiennej typufloat
. Aby to zrobić, musi istnieć niejawna konwersja zdouble
nafloat
. Nie ma takiej konwersji, ponieważ możesz (iw tym przypadku tracisz) informacje w konwersji.Powodem jest to, że wartość używana przez kompilator nie jest tak naprawdę 0,58, ale wartością zmiennoprzecinkową najbliższą 0,58, czyli 0,57999999999999978655962351581366 ... dla
double
i dokładnie 0,579999946057796478271484375 dlafloat
.Ściśle mówiąc,
f
nie jest to wymagane. Możesz uniknąć używaniaf
przyrostka, rzutując wartość nafloat
:float timeRemaining = (float)0.58;
źródło
(float) 0.58
działać? Powiedziałeś wcześniej, że nie ma konwersji, ponieważ informacje mogą zostać utracone, więc jak to się stanie, że obsada będzie działać?2.4
jest wszędzie interpretowane jako podwójne. 2. Niejawne konwersje zawężające (np. Z double na float) są niedozwolone. Jeśli chcesz zrobić wyjątek od tych zasad, musisz mieć bardzo dobry powód. Oszczędność jednego naciśnięcia klawisza raczej nie wystarczy.Ponieważ istnieje kilka typów numerycznych, że kompilator może wykorzystać do reprezentowania wartości
0.58
:float
,double
idecimal
. O ile nie zgadzasz się z tym, że kompilator wybiera jeden za Ciebie, musisz ujednoznacznić.Dokumentacja dla
double
stwierdza, że jeśli sam nie określisz typu, kompilator zawsze wybierzedouble
jako typ dowolnego rzeczywistego literału numerycznego:Dołączenie sufiksu
f
tworzyfloat
; przyrostekd
tworzydouble
; przyrostekm
tworzydecimal
. Wszystkie te działają również z wielkich liter.Jednak to wciąż nie wystarczy, aby wyjaśnić, dlaczego to się nie kompiluje:
float timeRemaining = 0.58;
Brakująca połowa odpowiedzi polega na tym, że konwersja z wersji
double
0.58
nafloat
timeRemaining
potencjalnie traci informacje, więc kompilator odmawia jej niejawnego zastosowania. Jeśli dodasz jawne rzutowanie, zostanie wykonana konwersja; jeśli dodaszf
sufiks, konwersja nie będzie potrzebna. W obu przypadkach kod byłby następnie kompilowany.źródło
int
i jedną zadouble
.double a = 0.69f;
?float
nadouble
.Problem polega na tym, że .NET, aby umożliwić wykonywanie niektórych typów niejawnych operacji obejmujących
float
idouble
, musiał albo jawnie określić, co powinno się zdarzyć we wszystkich scenariuszach obejmujących operandy mieszane, albo zezwolić na niejawne konwersje między typami, które mają być wykonywane w jednym tylko kierunek; Microsoft zdecydował się pójść za przykładem Javy, dopuszczając kierunek, który czasami sprzyja precyzji, ale często rezygnuje z poprawności i generalnie powoduje kłopoty.W prawie wszystkich przypadkach, biorąc plik
double
wartość, która jest najbliższa określonej wielkości liczbowej i przypisując ją do afloat
, dajefloat
wartość, która jest najbliższa tej samej wielkości. Istnieje kilka przypadków narożnych, takich jak wartość 9,007,199,791,611,905; najlepszafloat
reprezentacja wyniosłaby 9 007 200 328 482 816 (co jest mniej o 536 870 911), ale rzucenie najlepszejdouble
reprezentacji (tj. 9 007 199 791 611 904)float
daje 9 007 199 254 740 992 (co jest mniejsze o 536 870 913). Jednak ogólnie rzecz biorąc, przekształcenie najlepszejdouble
reprezentacji pewnej wielkości nafloat
da albo najlepszą możliwąfloat
reprezentację, albo jedną z dwóch reprezentacji, które są zasadniczo równie dobre.Zauważ, że to pożądane zachowanie ma zastosowanie nawet w skrajnych przypadkach; na przykład najlepsza
float
reprezentacja wielkości 10 ^ 308 jest zgodna zfloat
reprezentacją uzyskaną przez przekształcenie najlepszejdouble
reprezentacji tej wielkości. Podobnie najlepszafloat
reprezentacja 10 ^ 309 odpowiadafloat
reprezentacji uzyskanej przez przekształcenie najlepszejdouble
reprezentacji tej wielkości.Niestety, konwersje w kierunku, który nie wymaga wyraźnego rzutowania, rzadko są tak dokładne. Konwertowanie najlepszych
float
reprezentacji wartości nadouble
rzadko daje coś szczególnie bliskiego najlepszejdouble
reprezentacji tej wartości, aw niektórych przypadkach wynik może różnić się o setki rzędów wielkości (np. Przekształcenie najlepszejfloat
reprezentacji 10 ^ 40 nadouble
da wartość, która w porównaniu jest większa niż najlepszadouble
reprezentacja 10 ^ 300.Niestety, reguły konwersji są tym, czym są, więc trzeba żyć z używaniem głupich typów i przyrostków podczas konwersji wartości w „bezpiecznym” kierunku i uważać na niejawne typy w niebezpiecznym kierunku, które często dają fałszywe wyniki.
źródło