Powiedzmy, że mam wartość 3,4679 i chcę 3,46, jak mogę to skrócić do dwóch miejsc po przecinku bez zaokrąglania w górę?
Próbowałem następujących rzeczy, ale wszystkie trzy dają mi 3,47:
void Main()
{
Console.Write(Math.Round(3.4679, 2,MidpointRounding.ToEven));
Console.Write(Math.Round(3.4679, 2,MidpointRounding.AwayFromZero));
Console.Write(Math.Round(3.4679, 2));
}
Zwraca to 3.46, ale wydaje się po prostu brudne:
void Main()
{
Console.Write(Math.Round(3.46799999999 -.005 , 2));
}
Bardziej przydatne byłoby posiadanie pełnej funkcji obcięcia ułamka dziesiętnego w języku C # w świecie rzeczywistym. Można to łatwo przekonwertować na metodę rozszerzenia Decimal, jeśli chcesz:
Jeśli potrzebujesz VB.NET, spróbuj tego:
Następnie użyj tego w ten sposób:
lub
źródło
Użyj operatora modułu:
wynik: 0,54
źródło
0.5400
... Odpowiedź D. Nesterova poniżej dała oczekiwane0.54
.$"{0.54m:C}"
produkuje"$0.54"
i tak,$"{0.5400m:C}"
produkuje"$0.54"
.Uniwersalna i szybka metoda (bez
Math.Pow()
/ mnożenia) dlaSystem.Decimal
:źródło
Problem z innymi przykładami polega na tym, że mnożą one wartość wejściową przed jej podzieleniem. Jest tu przypadek skrajny, w którym można przepełnić dziesiętne, mnożąc najpierw, przypadek krawędziowy, ale coś, z czym się spotkałem. Bezpieczniej jest osobno zająć się częścią ułamkową w następujący sposób:
źródło
Zostawię rozwiązanie dla liczb dziesiętnych.
Niektóre rozwiązania dotyczące liczb dziesiętnych są tutaj podatne na przepełnienie (jeśli podamy bardzo dużą liczbę dziesiętną, a metoda spróbuje ją pomnożyć).
Rozwiązanie Tima Lloyda jest chronione przed przepełnieniem, ale nie jest zbyt szybkie.
Poniższe rozwiązanie jest około 2 razy szybsze i nie ma problemu z przepełnieniem:
źródło
Truncate
metoda zostanie zgrupowana razem z natywnymi .net, zapewniając użytkownikowi bezproblemową obsługę .Assert.AreEqual(1.1m, 1.12m.TruncateEx(1));
zawodzi z tego powodu. Jeśli określisz „normalne” zaokrąglanie (AwayFromZero) w wywołaniu Math.Round, toAssert.AreEqual(0m, 0m.TruncateEx(1));
zakończy się niepowodzeniemMidpointRounding.AwayFromZero
i specjalnie kodu do obsługi wartości 0.To stare pytanie, ale wiele odpowiedzi nie działa dobrze lub przepełnia się przy dużych liczbach. Myślę, że odpowiedź D. Niestierowa jest najlepsza: solidna, prosta i szybka. Chcę tylko dodać moje dwa centy. Bawiłem się liczbami dziesiętnymi, a także sprawdzałem kod źródłowy . Z
public Decimal (int lo, int mid, int hi, bool isNegative, byte scale)
dokumentacji konstruktora .Wiedząc o tym, moje pierwsze podejście polegało na stworzeniu kolejnej,
decimal
której skala odpowiada liczbom dziesiętnym, które chciałem odrzucić, a następnie skrócić ją i ostatecznie utworzyć ułamek dziesiętny z pożądaną skalą.Ta metoda nie jest szybsza niż metoda D. Niestierowa i jest bardziej złożona, więc bawiłem się trochę więcej. Domyślam się, że konieczność stworzenia pomocniczego
decimal
i dwukrotnego pobrania bitów powoduje, że jest wolniejszy. Za drugim razem samodzielnie manipulowałem składnikami zwracanymi przez metodę Decimal.GetBits (Decimal d) . Chodzi o to, aby podzielić składniki 10 razy tyle razy, ile potrzeba i zmniejszyć skalę. Kod jest oparty (w dużym stopniu) na metodzie Decimal.InternalRoundFromZero (ref Decimal d, int decimalCount) .Nie przeprowadziłem rygorystycznych testów wydajności, ale na procesorze MacOS Sierra 10.12.6, 3,06 GHz Intel Core i3 i docelowym .NetCore 2.1 ta metoda wydaje się być znacznie szybsza niż D.Nesterov (nie podam liczb, ponieważ jak wspomniałem, moje testy nie są rygorystyczne). Każdy, kto to zaimplementuje, musi ocenić, czy wzrost wydajności opłaca się za dodatkową złożoność kodu.
źródło
czy to zadziała dla Ciebie?
źródło
Dałbyś
((long)(3.4679 * 100)) / 100.0
to, czego chcesz?źródło
Oto metoda rozszerzenia:
źródło
Jeśli nie martwisz się zbytnio o wydajność, a wynikiem końcowym może być ciąg, następujące podejście będzie odporne na problemy z płynną precyzją:
źródło
Oto moja implementacja funkcji LICZBA.CAŁK
źródło
a co z tym?
źródło
Oprócz powyższych rozwiązań możemy osiągnąć jeszcze jeden sposób.
źródło
W pewnych warunkach może to wystarczyć.
Miałem dziesiętną wartość SubCent = 0,0099999999999999999999999999M, która ma tendencję do formatowania do | SubCent: 0,010000 | via
string.Format("{0:N6}", SubCent );
i wiele innych opcji formatowania.Moim wymaganiem było nie zaokrąglanie wartości SubCent, ale też nie rejestrowanie każdej cyfry.
Następujące spełniły moje wymagania:
Która zwraca ciąg: | SubCent: 0,0099999 |
Aby pomieścić wartość mającą część całkowitą, poniżej podano początek.
Która zwraca ciąg:
źródło
Używam tej funkcji do obcinania wartości po przecinku w zmiennej ciągu
źródło
Oto co zrobiłem:
odejmowanie dwóch wprowadzonych liczb bez zaokrąglania miejsc po przecinku w górę lub w dół. bo inne rozwiązania u mnie nie działają. nie wiem, czy to zadziała u innych, po prostu chcę się tym podzielić :) Mam nadzieję, że zadziała jednak dla tych, którzy znajdują rozwiązanie problemu podobnego do mojego. Dzięki
PS: Jestem początkującym, więc śmiało mogę coś na ten temat wskazać. : D to jest dobre, jeśli faktycznie masz do czynienia z pieniędzmi, z powodu centów, prawda? ma tylko 2 miejsca po przecinku, a zaokrąglenie to nie, nie.
źródło
źródło
źródło
Właściwie chcesz 3,46 od 3,4679. To jest tylko reprezentacja znaków, więc nie ma to nic wspólnego z funkcją matematyczną, funkcja matematyczna nie jest przeznaczona do wykonywania tej pracy. Po prostu użyj poniższego kodu.
źródło
co powiesz na
źródło