To, co chciałbym, to metoda konwersji podwójnego na ciąg znaków, który zaokrągla metodę pół-w górę - tj. Jeśli liczba dziesiętna do zaokrąglenia wynosi 5, zawsze zaokrągla w górę do następnej liczby. Jest to standardowa metoda zaokrąglania, której większość ludzi oczekuje w większości sytuacji.
Chciałbym również, aby wyświetlane były tylko cyfry znaczące - tzn. Nie powinny być żadnych zer końcowych.
Wiem, że jedną z metod jest zrobienie tego String.format
:
String.format("%.5g%n", 0.912385);
zwroty:
0.91239
co jest świetne, jednak zawsze wyświetla liczby z 5 miejscami dziesiętnymi, nawet jeśli nie są znaczące:
String.format("%.5g%n", 0.912300);
zwroty:
0.91230
Inną metodą jest użycie DecimalFormatter
:
DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
zwroty:
0.91238
Jednak, jak widać, wykorzystuje to półokrągłe zaokrąglanie. Oznacza to, że zaokrągli w dół, jeśli poprzednia cyfra jest parzysta. Chciałbym to:
0.912385 -> 0.91239
0.912300 -> 0.9123
Jaki jest najlepszy sposób na osiągnięcie tego w Javie?
"#.##"
:, zaokrąglaniemHALF_UP
.256.335f
->"256.33"
... (przykład pochodzi z komentarzy do odpowiedzi @ asterite).Zakładając, że
value
todouble
można zrobić:To z dokładnością do 5 cyfr. Liczba zer wskazuje liczbę miejsc po przecinku.
źródło
Math.round(0.1 * Math.pow(10,20))/Math.pow(10,20) == 0.09223372036854775
.265.335
naprawdę oznacza265.335 += tolerance
, gdzie tolerancja zależy od poprzednich operacji i zakresu wartości wejściowych. Nie znamy prawdziwej, dokładnej wartości. Przy wartościach krańcowych każda odpowiedź jest prawdopodobnie poprawna. Jeśli musimy być dokładni, nie powinniśmy pracować podwójnie.fail
Tutaj nie jest w Nawrócenie podwójnie. W OP uważa, że może polegać na przychodzącym265.335
jako właśnie takim.dostaniesz
BigDecimal
. Aby uzyskać ciąg z niego, wystarczy zadzwonić, żeBigDecimal
„stoString
metodę lubtoPlainString
metody Java 5+ dla zwykłego formatu ciąg.Przykładowy program:
źródło
new BigDecimal(doubleVar)
ponieważ możesz mieć problemy z zaokrąglaniem zmiennoprzecinkowychdouble val = 265.335;
,BigDecimal.valueOf(val).setScale(decimals, BigDecimal.ROUND_HALF_UP).toPlainString();
=>265.34
, ale(new BigDecimal(val)).setScale(decimals, BigDecimal.ROUND_HALF_UP).toPlainString();
=>265.33
.Możesz także użyć
aby upewnić się, że masz końcowe 0.
źródło
RoundingMode.
Decimal mode
używaRoundingMode.HALF_EVEN.
Jak zauważyli inni, prawidłowa odpowiedź jest użycie albo
DecimalFormat
alboBigDecimal
. Liczba zmiennoprzecinkowa nie ma miejsc dziesiętnych, więc nie można zaokrąglić / obciąć określonej liczby w pierwszej kolejności. Musisz pracować z dokładnością dziesiętną i tak właśnie robią te dwie klasy.Zamieszczam następujący kod jako kontrprzykład na wszystkie odpowiedzi w tym wątku i rzeczywiście w całym StackOverflow (i gdzie indziej), które zalecają mnożenie, a następnie obcięcie, a następnie dzielenie. Zwolennicy tej techniki muszą wyjaśnić, dlaczego poniższy kod generuje nieprawidłowe dane wyjściowe w ponad 92% przypadków.
Wynik tego programu:
EDYCJA: Aby odpowiedzieć na niektóre komentarze poniżej, zmodyfikowałem część modułu pętli testowej za pomocą
BigDecimal
inew MathContext(16)
dla operacji modułu w następujący sposób:Wynik:
źródło
100 trials 94 errors
Powinieneś zacząć od pozytywnego wyniku testu i pokazać, że wprowadzenie zaokrąglania przerywa test.double
jak bez błędów ideone.com/BVCHh3Załóżmy, że masz
możesz użyć
BigDecimal
lub bez BigDecimal
z obu rozwiązań
d == 9232.13
źródło
RoundingMode.HALF_UP
jest złe. Wypróbuj z1.505
. Właściwym sposobem jest użycieBigDecimal.valueOf(d)
.Możesz użyć klasy DecimalFormat.
źródło
Double.valueOf()
którego wybranoDouble.parseDouble()
?valueOf()
Sposób powraca doDouble
przedmiotu, gdyparseDouble()
zwrócidouble
pierwotnej. Sposób, w jaki napisany jest bieżący kod, powoduje również zastosowanie automatycznego rozpakowywania do powrotu, aby rzutować go natwoDouble
operację podstawową oczekiwaną przez zmienną, dodatkową operację kodu bajtowego.parseDouble()
Zamiast tego zmieniłbym odpowiedź .Double.parseDouble()
potrzebujeString
wkładu.Real-Java Java How-to publikuje to rozwiązanie, które jest również kompatybilne z wersjami wcześniejszymi niż Java 1.6.
źródło
źródło
Math.floor(x + 0.5)
orazMath.round(x)
@Milhous: format dziesiętny dla zaokrąglania jest doskonały:
Dodałbym, że ta metoda jest bardzo dobra w zapewnianiu rzeczywistego numerycznego, zaokrąglającego mechanizmu - nie tylko wizualnie, ale także podczas przetwarzania.
Hipotetyczny: musisz zaimplementować mechanizm zaokrąglania w programie GUI. Aby zmienić dokładność / precyzję wyniku, wystarczy zmienić format karetki (tzn. W nawiasach kwadratowych). Po to aby:
zwróci jako wynik:
0.912385
zwróci jako wynik:
0.91239
zwróci jako wynik:
0.9124
[EDYCJA: również jeśli format karetki jest podobny („# 0. ############”) i wprowadzasz liczbę dziesiętną, np. 3.1415926, ze względu na argument, DecimalFormat nie generuje żadnych śmieci ( np. końcowe zera) i zwróci:
3.1415926
jeśli jesteś w ten sposób skłonny. To prawda, że jest trochę gadatliwy, jeśli chodzi o upodobania niektórych twórców - ale hej, ma on mało pamięci podczas przetwarzania i jest bardzo łatwy do wdrożenia.]Zasadniczo piękno DecimalFormat polega na tym, że jednocześnie obsługuje on wygląd sznurka - a także poziom dokładności zaokrąglania. Ergo: zyskujesz dwie korzyści w cenie jednej implementacji kodu. ;)
źródło
double
. Użyj BigDecimal lub dowolnego innego formatu dziesiętnego.Oto podsumowanie tego, czego możesz użyć, jeśli chcesz uzyskać wynik w postaci ciągu:
DecimalFormat # setRoundingMode () :
BigDecimal # setScale ()
Oto propozycja bibliotek, których możesz użyć, jeśli chcesz
double
. Nie polecałbym go jednak do konwersji ciągów, ponieważ double może nie być w stanie dokładnie przedstawić tego, co chcesz (patrz np. Tutaj ):Precyzja z Apache Commons Math
Funkcje od Colta
Używa od Weka
źródło
Możesz użyć następującej metody narzędzia
źródło
round(1.005,2);
lubround(0.50594724957626620092, 20);
Zwięzłe rozwiązanie:
Zobacz także https://stackoverflow.com/a/22186845/212950 Dziękujemy jpdymond za zaoferowanie tego.
źródło
Możesz użyć BigDecimal
Patrz: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/
źródło
Spróbuj tego: org.apache.commons.math3.util.Precision.round (podwójne x, skala int)
Zobacz: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html
Strona główna Biblioteki Matematycznej Apache Commons: http://commons.apache.org/proper/commons-math/index.html
Wewnętrzna implementacja tej metody to:
źródło
Ponieważ nie znalazłem pełnej odpowiedzi na ten temat, stworzyłem klasę, która powinna sobie z tym poradzić poprawnie, ze wsparciem dla:
Użycie jest dość proste :
(Na potrzeby tego przykładu używam niestandardowych ustawień regionalnych)
Oto klasa :
źródło
Jeśli naprawdę chcesz liczb dziesiętnych do obliczeń (i nie tylko do danych wyjściowych), nie używaj binarnego formatu zmiennoprzecinkowego, takiego jak double.
Używam BigDecimal do obliczeń, ale pamiętaj, że zależy to od wielkości liczb, z którymi masz do czynienia. W większości moich implementacji analiza składni z podwójnej lub całkowitej na Long jest wystarczająca do obliczeń bardzo dużej liczby.
W rzeczywistości niedawno użyłem analizy składniowej do uzyskania długiej reprezentacji (w przeciwieństwie do wyników szesnastkowych) w interfejsie GUI dla liczb tak dużych, jak ################## ############### znaków (jako przykład).
źródło
Aby to osiągnąć, możemy użyć tego formatyzatora:
lub:
Użyj tej metody, aby uzyskać zawsze dwa miejsca po przecinku:
Definiowanie tych wartości:
Za pomocą metody możemy uzyskać następujące wyniki:
demo online.
źródło
Na wypadek, gdyby ktoś nadal potrzebował pomocy w tym zakresie. To rozwiązanie działa dla mnie idealnie.
zwraca a
String
z żądanym wyjściem.źródło
Zgadzam się z wybraną odpowiedzią na użycie
DecimalFormat
--- lub alternatywnieBigDecimal
.Najpierw przeczytaj aktualizację poniżej!
Jeśli jednak nie chcesz zaokrąglić podwójnej wartości i uzyskaćdouble
wynik wartości, można użyćorg.apache.commons.math3.util.Precision.round(..)
jak wspomniano powyżej. Implementacja używaBigDecimal
, jest powolna i powoduje śmieci.Podobna, ale szybka i pozbawiona śmieci metoda jest udostępniana przezDoubleRounder
narzędzie w bibliotece decimal4j:Wyjdzie
Zobacz https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility
Uwaga: Jestem zaangażowany w projekt decimal4j.
Aktualizacja: Jak zauważył @iaforek, DoubleRounder czasami zwraca wyniki sprzeczne z intuicją. Powodem jest to, że dokonuje matematycznie poprawnego zaokrąglania. Na przykład
DoubleRounder.round(256.025d, 2)
zostanie zaokrąglony w dół do 256.02, ponieważ podwójna wartość reprezentowana jako 256.025d jest nieco mniejsza niż wartość wymierna 256.025, a zatem zostanie zaokrąglona w dół.Uwagi:
BigDecimal(double)
konstruktora (ale nie dovalueOf(double)
którego używa konstruktora łańcucha).Z tych powodów i wszystkiego wymienionego powyżej w tym poście nie mogę polecić korzystania z DoubleRounder .
źródło
Poniższy fragment kodu pokazuje, jak wyświetlać n cyfr. Sztuczka polega na ustawieniu zmiennej pp na 1, po której następuje n zer. W poniższym przykładzie zmienna pp ma 5 zer, więc wyświetli się 5 cyfr.
źródło
Jeśli używasz
DecimalFormat
konwertowaćdouble
doString
, to jest bardzo proste:Do wyboru jest kilka
RoundingMode
wartości wyliczania, w zależności od wymaganego zachowania.źródło
Przybyłem tu tylko z prostą odpowiedzią, jak zaokrąglić liczbę. To jest dodatkowa odpowiedź na to pytanie.
Jak zaokrąglić liczbę w Javie
Najczęstszym przypadkiem jest użycie
Math.round()
.Liczby są zaokrąglane do najbliższej liczby całkowitej.
.5
Wartość jest zaokrąglone. Jeśli potrzebujesz innego zachowania zaokrąglania niż to, możesz użyć jednej z innych funkcji matematycznych . Zobacz porównanie poniżej.okrągły
Jak wspomniano powyżej, zaokrągla to do najbliższej liczby całkowitej.
.5
miejsca po przecinku w górę. Ta metoda zwracaint
.stropować
Każda wartość dziesiętna jest zaokrąglana w górę do następnej liczby całkowitej. Idzie do sufitu . Ta metoda zwraca a
double
.piętro
Każda wartość dziesiętna jest zaokrąglana w dół do następnej liczby całkowitej. Ta metoda zwraca a
double
.rint
Jest to podobne do zaokrąglania w tych wartościach dziesiętnych zaokrąglanych do najbliższej liczby całkowitej. Jednak w odróżnieniu od
round
,.5
wartości zaokrąglić do parzystej liczby całkowitej. Ta metoda zwraca adouble
.źródło
Jeśli używasz technologii, która ma minimalny pakiet JDK. Oto sposób bez bibliotek Java:
źródło
DecimalFormat jest najlepszym sposobem na wyjście, ale nie wolę tego. Zawsze robię to cały czas, ponieważ zwraca podwójną wartość. Więc mogę użyć tego więcej niż tylko danych wyjściowych.
LUB
Jeśli potrzebujesz dużej liczby miejsc dziesiętnych, możesz zamiast tego użyć BigDecimal. W każdym razie
.0
jest to ważne. Bez tego zaokrąglenie 0.33333d5 zwraca 0.33333 i dozwolone jest tylko 9 cyfr. Druga funkcja bez.0
ma problemy ze zwrotem 0.30000 0.30000000000000004.źródło
oto moja odpowiedź:
źródło
Więc po przeczytaniu większości odpowiedzi zdałem sobie sprawę, że większość z nich nie będzie precyzyjna, w rzeczywistości użycie
BigDecimal
wydaje się najlepszym wyborem, ale jeśli nie zrozumiesz, jakRoundingMode
działa, nieuchronnie stracisz precyzję. Zrozumiałem to podczas pracy z dużymi liczbami w projekcie i pomyślałem, że może to pomóc innym w problemach z zaokrąglaniem liczb. Na przykład.Spodziewałbyś się uzyskać
1363.28
jako wynik, ale skończysz z1363.27
, co nie jest oczekiwane, jeśli nie wiesz, coRoundingMode
robi. Patrząc na Dokumenty Oracle , znajdziesz następujący opisRoundingMode.HALF_UP
.Wiedząc o tym, zdaliśmy sobie sprawę, że nie uzyskamy dokładnego zaokrąglenia, chyba że będziemy chcieli zaokrąglić w kierunku najbliższego sąsiada . Tak więc, aby uzyskać odpowiednią rundę, musielibyśmy zapętlać
n-1
cyfry dziesiętne w kierunku pożądanych cyfr dziesiętnych. Na przykład.W rezultacie otrzymamy oczekiwaną wydajność, która byłaby
1363.28
.źródło
Gdzie dp = pożądane miejsce po przecinku, a wartość jest podwójna.
źródło
1.0
dlavalue = 1.005
idp = 2
. Zamiast tego użyj tego .Należy pamiętać, że String.format () i DecimalFormat wytwarzają ciąg znaków przy użyciu domyślnych ustawień regionalnych. Mogą więc pisać sformatowaną liczbę z kropką lub przecinkiem jako separator między liczbami całkowitymi i dziesiętnymi. Aby upewnić się, że zaokrąglony ciąg znaków ma format, którego chcesz użyć, java.text.NumberFormat jako:
Zostanie wydrukowany w języku angielskim (bez względu na lokalizację): 0,99 123,57 123,00
Przykład pochodzi z Farenda - jak poprawnie przekonwertować double na String .
źródło
Ogólnie zaokrąglanie odbywa się poprzez skalowanie:
round(num / p) * p
źródło