Przykład:
float timeRemaining = 0.58f;
Dlaczego f
na końcu tego numeru jest wymagana litera?
Przykład:
float timeRemaining = 0.58f;
Dlaczego f
na końcu tego numeru jest wymagana litera?
double & int
.
Odpowiedzi:
Twoja deklaracja pływaka składa się z dwóch części:
timeRemaining
jest typu float
.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 typu float
. Aby to zrobić, musi istnieć niejawna konwersja z double
na float
. 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 dla float
.
Ściśle mówiąc, f
nie jest to wymagane. Możesz uniknąć używania f
przyrostka, rzutując wartość na float
:
float timeRemaining = (float)0.58;
(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
i decimal
. 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 wybierze double
jako typ dowolnego rzeczywistego literału numerycznego:
Domyślnie prawdziwy literał numeryczny po prawej stronie operatora przypisania jest traktowany jako double. Jeśli jednak chcesz, aby liczba całkowita była traktowana jako podwójna, użyj sufiksu d lub D.
Dołączenie sufiksu f
tworzy float
; przyrostek d
tworzy double
; przyrostek m
tworzy decimal
. 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
na float
timeRemaining
potencjalnie traci informacje, więc kompilator odmawia jej niejawnego zastosowania. Jeśli dodasz jawne rzutowanie, zostanie wykonana konwersja; jeśli dodasz f
sufiks, konwersja nie będzie potrzebna. W obu przypadkach kod byłby następnie kompilowany.
int
i jedną za double
.
double a = 0.69f;
?
float
na double
.
Problem polega na tym, że .NET, aby umożliwić wykonywanie niektórych typów niejawnych operacji obejmujących float
i double
, 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 a float
, daje float
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; najlepsza float
reprezentacja wyniosłaby 9 007 200 328 482 816 (co jest mniej o 536 870 911), ale rzucenie najlepszej double
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 najlepszej double
reprezentacji pewnej wielkości na float
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 z float
reprezentacją uzyskaną przez przekształcenie najlepszej double
reprezentacji tej wielkości. Podobnie najlepsza float
reprezentacja 10 ^ 309 odpowiada float
reprezentacji uzyskanej przez przekształcenie najlepszej double
reprezentacji tej wielkości.
Niestety, konwersje w kierunku, który nie wymaga wyraźnego rzutowania, rzadko są tak dokładne. Konwertowanie najlepszychfloat
reprezentacji wartości na double
rzadko daje coś szczególnie bliskiego najlepszej double
reprezentacji tej wartości, aw niektórych przypadkach wynik może różnić się o setki rzędów wielkości (np. Przekształcenie najlepszej float
reprezentacji 10 ^ 40 na double
da wartość, która w porównaniu jest większa niż najlepsza double
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.
double
.