Rzut podwójnej zmiennej na dziesiętny

96

W jaki sposób można rzucić doublena decimalktóry jest używany podczas opracowywania waluty. Gdzie to Midzie?

decimal dtot = (decimal)(doubleTotal);
flo
źródło

Odpowiedzi:

85

Używasz tylko Mdla literału numerycznego, kiedy przesyłasz to tylko:

decimal dtot = (decimal)doubleTotal;

Zauważ, że liczba zmiennoprzecinkowa nie nadaje się do przechowywania dokładnej wartości, więc jeśli najpierw dodasz liczby do siebie, a następnie przekonwertujesz na Decimal, możesz uzyskać błędy zaokrągleń. Możesz chcieć przekonwertować liczby na Decimalprzed dodaniem ich do siebie lub upewnić się, że liczby nie są liczbami zmiennoprzecinkowymi w pierwszej kolejności.

Guffa
źródło
jako pytanie uzupełniające, dlaczego potrzebna jest wyraźna konwersja? Wypróbowałem to i otrzymuję błąd, że podwójna nie może być jawnie rzutowana na ułamek dziesiętny, ale czy liczba dziesiętna nie zapewnia większej precyzji? (tj. podobnie jak rzutowanie z int na double może być niejawne.)
4
@Cortana: Dokładność ułamka dziesiętnego jest wyższa, ale zakres jest mniejszy. Podwójna wartość może być poza zakresem dla ułamka dziesiętnego. Zobacz: stackoverflow.com/questions/7817866/…
Guffa
41

Możesz rzucić podwójną na dziesiętną w ten sposób, bez potrzeby Mdosłownego sufiksu:

double dbl = 1.2345D;
decimal dec = (decimal) dbl;

Powinieneś użyć Mprzy deklarowaniu nowej dosłownej wartości dziesiętnej:

decimal dec = 123.45M;

(Bez M123.45 jest traktowane jako podwójne i nie zostanie skompilowane).

Chris Fulstow
źródło
28

użyj domyślnej klasy konwersji: Convert.ToDecimal(Double)

Timur Sadykov
źródło
1
Nie, ponieważ spowoduje to zgłoszenie OverflowException double vol_y = (double) Decimal.MaxValue + 10E + 28D; Console.WriteLine ("Convert.ToDecimal (vol_y) =" + Convert.ToDecimal (vol_y));
TOXINE
2
@ToXinE IMHO w większości przypadków OverflowException jest lepszy niż
ciche
16
Convert.ToDecimal(the double you are trying to convert);
Tomek
źródło
2
Dowiedziałem się, że klasa Convert jest znacznie bardziej elastyczna i bezpieczniejsza niż rzutowanie w C #.
Tom
3
"Bezpieczny"? jak w sytuacji, gdy nie może rzucać, zgłasza wyjątek w czasie wykonywania zamiast błędu kompilatora? Ugryzło mnie to tyle razy, że aktywnie unikam Convert ...
Peter Ritchie
8
Wątek @PeterRitchie jest trochę stary, ale należy powiedzieć: bezpośrednie wywołanie metody Convert byłoby bardziej odpowiednim podejściem. Może jestem tylko maniakiem optymalizacji, ale jedna instrukcja mniej do rozwiązania to bonus (ponieważ użycie jawnej składni rzutowania (Type) jest po prostu przeciążeniem operatora, które wywołuje Convert).
Mike Johnson
2
@PeterRitchie: Z punktu widzenia projektowania języka, byłoby lepiej wymagać od programisty używania jednej z dwóch metod konwersji, zamiast pozwalać na rzutowanie typu od doubledo decimal, biorąc pod uwagę, że dla doublewartości takiej jak (1000000.0 / 3.0) w niektórych przypadkach chcą obciąć „nadmiar” precyzji, uzyskując 333333,333333333D, ale w innych przypadkach chcielibyśmy ją zachować, uzyskując 333333,333333333313931D. Zamiast po prostu mówić „przekonwertuj na liczbę dziesiętną”, kod powinien określać sposób wykonania tej konwersji.
supercat
2
@supercat, który naprawdę wydaje się niezwiązany z moim pierwszym komentarzem, ponieważ używanie Convert.ToDecimal(double)jest takie samo jak (decimal)doubleTotal, z wyjątkiem tego, że jeśli zostanie doubleTotalzmieniony na inny typ, prawdopodobnie unikniesz błędu w czasie kompilacji i wprowadzisz trudniejszy do znalezienia błąd czasu wykonywania, ponieważ inny ToDecimal nadpisanie może zostać wywołane. Operator obsady jest dużo bardziej dosadny ...
Peter Ritchie
1

Cóż, to stare pytanie i rzeczywiście skorzystałem z niektórych z przedstawionych tutaj odpowiedzi. Niemniej jednak w moim konkretnym scenariuszu było możliwe, że doublewartość, na którą chciałem przeliczyć, decimalbyła często większa niż decimal.MaxValue. Tak więc zamiast obsługiwać wyjątki napisałem tę metodę rozszerzenia:

    public static decimal ToDecimal(this double @double) => 
        @double > (double) decimal.MaxValue ? decimal.MaxValue : (decimal) @double;

Powyższe podejście działa, jeśli nie chcesz zawracać sobie głowy obsługą wyjątków przepełnienia i jeśli coś takiego się wydarzy, chcesz po prostu zachować maksymalną możliwą wartość (mój przypadek), ale mam świadomość, że w wielu innych scenariuszach nie byłoby to oczekiwane zachowanie i może być potrzebna obsługa wyjątków.

taquion
źródło
1
To się nie powiedzie w następującym przypadku double _double = (double) decimal.MaxValue; Sugerowałbym użycie> = w porównaniu publiczne statyczne dziesiętne ToDecimal (to podwójne _double) => _double> = (double) decimal.MaxValue? decimal.MaxValue: (decimal) _double;
Martin Eyles