zaokraglenie liczby float/double do n miejsc po przecinku

0

Mam taki kod. Jak parsuje liczby to wyniki sa zadowalajace. Odpowiednio 5 i -5.57. Kiedy jednak dodam je to wynikiem jest -0.5700000000000003.

String str1="5";
String str2="-5.57";
double x1=Double.parseDouble(str1);
double x2=Double.parseDouble(str2);
System.out.println(x1 + "+" + x2);
double z=x1+x2;
System.out.println(z);

Oczywiscie wynika to z tego ze po zparsowaniu liczba ma np na 20 miejscu po przecinku jakas wartosc (pomimo ze 19 pierwszych to zera) wyswietlanych jest 16 miejsc po przecinku, wiec po zsumowaniu dwoch takich liczb moze sie okazac ze jakas cyfra juz sie pojawi na tym 16 miejscu i tak wlasnie jest w tym przypadku. Pytanie brzmi: Jak zaokraglic liczbe double/float do n-tego miejsca po przecinku? (Chyba ze ktos ma jakis inny pomysl)

0

moze czyszczenie najmniej znaczacych bitow w mantysie ?

0

Mozna zrobic tak:

z=new BigDecimal(z).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

tylko ze poszykuje czegos bardziej wydajnego (dla kilkunastu milionow operacji to niestety juz widac roznice ze sie muli). Mozesz flabra napisac jak wykonac to z mantysa? Chetnie zobacze jak to zrobic.

0

tylko dla double (8 bajtowych floatow)

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char uchar;

inline char getbit(void* buf,ulong bit){
  return (char)((((uchar*)buf)[bit>>3]>>((uchar)(bit&7)))&1);
}

inline void* zerobit(void* buf,ulong bit){
  int i=(bit>>3);
  ((uchar*)buf)[i]&=(uchar)(~((uchar)(1<<(bit&7))));
  return buf;
}

void wyzerujmantyse(double* n,ulong ilebitow=0){
  if((!ilebitow)||(ilebitow>52))ilebitow=52;  // 52 rozmiar mantysy
  int i=0;
  while(i<ilebitow && !getbit(n,i))i++;
  int j=i;
  while(i<ilebitow && getbit(n,i))i++;
  while((i--)>j)zerobit(n,i);
}

int main(){
  double n=1.5;
  n+=0.125;
  printf("%f\n",n);
  wyzerujmantyse(&n);
  printf("%f\n",n);
  return 0;
}

metoda taka, ze wyszukuje pierwszy zapalony bit w mantysie (od najmniej znaczacego) do ostatniego zapalonego bitu lub do wskazanej ilosci. potem je zeruje. wiec dl przykladowego 0011001100 po wykonaniu mantysa bedzie wygladac tak: 0011000000

dla innych typow niz double musisz sobie odpowiednio znalezc dlugosc mantysy.

//ups hmm cos mnie zmylilo i myslalem ze o c chodzi

0

Dżi, ludzie bez przesady: "czyszczenie" bitów mantysy?!

axiomat napisał(a)

Pytanie brzmi: Jak zaokraglic liczbe double/float do n-tego miejsca po przecinku? (Chyba ze ktos ma jakis inny pomysl)

import java.lang.*;
import java.text.NumberFormat;

class Main {

    static void print(double d) {
        NumberFormat nf = NumberFormat.getInstance();
        nf.setMaximumFractionDigits(5);
        String string = nf.format( d );
        System.out.println( string );
    }

    public static void main(String[] args) {
        String str1="5";
        String str2="-5.57";
        double x1=Double.parseDouble(str1);
        double x2=Double.parseDouble(str2);
        System.out.println(x1 + "+" + x2);
       
        print(x1+x2);
    }
}
5.0+-5.57
-0,57
0

Wiesz co marcinEc? To tez nie jest zbyt wydajne... poza tym wynikiem jest String, a wiec znow musialbym rzutowac na double... lepiej juz dziala z tym:

z=new BigDecimal(z).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

przynajmniej jest to liczba i ma faktycznie wyciete to co niepotrzebne. Co do wycinania mantysy to flabra podal kod w C (a ta czesc forum dotyczy Jav'y :] ) i rzeczywiscie dziala... nawet skutecznie... tylko ze w javie przesuniecia bitowe sa dopuszczalne tylko na liczbach calkowitych (float double odpadaja)... przynajmniej z tego co sie zorientowalem.

0
axiomat napisał(a)

tylko ze w javie przesuniecia bitowe sa dopuszczalne tylko na liczbach calkowitych (float double odpadaja)... przynajmniej z tego co sie zorientowalem.

przyjrzyj się, tam wlasnie nie ma zadnego przesuniecia na floatach :> nota bene tez niedozwolonych w c/cpp dla tych typow. więc jeśli ten kod da się przerobić na javę..

marcinEc opanuj sie i skończ ze swoim krytykowaniem wszystkiego czego sam nie napiszesz, filozofia "jedynie słusznych" rozwiązań odeszla w niepamiec i przypominana jest raczej jako humorystyczne okreslenie. zawsze proponujesz rozwiązania wysokiego poziomu, ktore nie zawsze w ogole potrzebne

0

:D
Ale o co Ci chodzi?! Przecież DODAWANIE dwóch liczb double x1 i x2 da w wyniku double, a błąd związany jest z REPREZENTACJĄ binarną liczb zmiennoprzecinkowych, tzn. WYDRUK tej liczby może dać na oddalonej pozycji pewien błąd, i ten błąd jest ZAWSZE dla liczb, których nie można dobrze reprezentować w ułamku binarnym... Po to jest ZAOKRĄGLANIE przy WYDRUKU [jeśli ktoś wie to niech napisze: dlaczego out.print(x) daje 0.7999999999999, a formatowanie przez np. NumberFormat da 0.8? bo mie się nie chce szukać ;-P]
Bardziej pojemny typ -> mniejszy błąd, większy czas obliczeń.

0
flabra napisał(a)

marcinEc opanuj sie i skończ ze swoim krytykowaniem wszystkiego czego sam nie napiszesz, filozofia "jedynie słusznych" rozwiązań odeszla w niepamiec i przypominana jest raczej jako humorystyczne okreslenie. zawsze proponujesz rozwiązania wysokiego poziomu, ktore nie zawsze w ogole potrzebne

Człowieku, odwal się ode mnie i pomyśl nad swoimi udziwnionym rozwiązaniem, albo napisz PO CO tak trzeba w tym przypadku... i co to w ogóle ma zrobić?

0

blad powstaje po dodaniu dwoch liczb, niech teraz bedzie sytuacja ze trzeba ten wynik prownac czy aby na pewno jest rowny jakiejs liczbie. Niech bedzie tak jak w przykladzie (5) + (-5.57) czy ten wynik jest rowny -0.57? Nie, wiec jakas czesc kodu po if sie nie wykona. Trzeba co s zrobic aby wynik byl dokladnie iles tam. jesli teraz bede sumowal jakies kwoty (np. rachunki ) i mam ich kilkanascie milionow to blad moze wejsc juz na znaczace pozycje :( a zaokraglanie po kazdym zsumowaniu powoduje spore opoznienie. MarcinEc masz racje ze im wymagana wieksza dokladnosc tym niestety kod jest wolniejszy... ale czy naprawde nie ma czegos sensownego? Do jasnej cholery, niech mi ktos da namiary goscia (choc pewnie sie staral zeby to dobrze zrobic) ktory napisal metode do parsowania (Double.parseDouble(str1)) to go odwiedze ;P

0
axiomat napisał(a)

blad powstaje po dodaniu dwoch liczb, niech teraz bedzie sytuacja ze trzeba ten wynik prownac czy aby na pewno jest rowny jakiejs liczbie. Niech bedzie tak jak w przykladzie (5) + (-5.57) czy ten wynik jest rowny -0.57? Nie, wiec jakas czesc kodu po if sie nie wykona.

Liczby zmiennoprzecinkowe takie są! Nic z tym nie zrobisz! Porównywania dokonuje się w pewnej ustalonej granicy, np. delta=0.00001, porównanie: if( abs(a-b) < delta ) then Liczby są równe.

axiomat napisał(a)

Trzeba co s zrobic aby wynik byl dokladnie iles tam.

Ale tak się nie da dla każdej liczby przy kodowaniu binarnym. Da się np. dla 0,5; 0,25; itd. czy ich sumy; reszta to przybliżenia, dość dokładne nawet...

axiomat napisał(a)

jesli teraz bede sumowal jakies kwoty (np. rachunki ) i mam ich kilkanascie milionow to blad moze wejsc juz na znaczace pozycje :( a zaokraglanie po kazdym zsumowaniu powoduje spore opoznienie.

Właśnie po to są reprezentaje liczb specjalnie stworzone do tego celu, np. BCD, przechowywanie jako znaki, typy w stylu Monetary, itp. co JEST oczywiście wolniejsze...

axiomat napisał(a)

MarcinEc masz racje ze im wymagana wieksza dokladnosc tym niestety kod jest wolniejszy... ale czy naprawde nie ma czegos sensownego? Do jasnej cholery, niech mi ktos da namiary goscia (choc pewnie sie staral zeby to dobrze zrobic) ktory napisal metode do parsowania (Double.parseDouble(str1)) to go odwiedze ;P

Liczby typu double są tak przechowywane, muszą być zapisane na skończonej liczbie bitów. Inne rozwiązania już wspomniałem - oczywiście nie tak szybkie, tylko pytanie: czy naprawdę potrzebujesz szybkości, a nie jakości? Na jakiś kompromis ostatecznie możesz pójść, np. olać te błędy w reprezetacji double (oczywiście jeżeli możesz na to sobie pozolić... dla kwot pieniężnych NIE możesz).

0

Wiesz co MarcinEc? Teoretycznie to moge... tak jak w Hacker'ach (film oczywiscie) bede przelewal te koncowki (grosze) na swoje konto az zbiore kilka milionow $ i wyjade na Hawaje :] A tak powaznie to rzeczywiscie chyba trzeba bedzie sie skupic na jakosci a nie szybkosci (jak w zyciu... musi byc jakis kompromis)

0

Panie i panowie, przelom w tej sprawie. Problem okazal sie wyjatkowo prosty do rozwiazania [wstyd] . Ponizej funkcja zaokraglajaca do dwoch miejsc po przecinku:

public double ZaokraglenieDouble (double z)
{
z=z*100;
int A=(int)z;
z=A;
z=z/100;
return z;
}

czas wykonania 1 miliona takich operacji zaokraglenia to 111 ms.
Dla porownania operacja:

public double Zaokragl_2 (double z)
{
z=new BigDecimal(z).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
return z;
}

to 13320 ms !!!!!!! Bez komentarza... Temat uwazam za skonczony, chyba ze ktos wpadnie na cos jeszcze szybszego :]

0

:)
No tak... Hmm, trochę nie rozumiem co chcesz osiągnąć? Jeśli błąd jest w reprezentacji to i tak będziesz miał obliczenia z błędem.
Spójrz na taki kod:

        NumberFormat nf = NumberFormat.getInstance();
        nf.setMinimumFractionDigits(2);
        for (double x=0.0; x<=1.0; x+=0.1) {
            System.out.println( "print\t" + x );
            System.out.println( "ZD\t" + ZaokraglenieDouble( x ) );
            System.out.println( "NF\t" + nf.format( x ) );
        }

Co daje:

print   0.0
ZD      0.0
NF      0,00
print   0.1
ZD      0.1
NF      0,10
print   0.2
ZD      0.2
NF      0,20
print   0.30000000000000004
ZD      0.3
NF      0,30
print   0.4
ZD      0.4
NF      0,40
print   0.5
ZD      0.5
NF      0,50
print   0.6
ZD      0.6
NF      0,60
print   0.7
ZD      0.7
NF      0,70
print   0.7999999999999999
ZD      0.8 [tu jeszcze OK]
NF      0,80
print   0.8999999999999999
ZD      0.89 [!!!blad!!!]
NF      0,90
print   0.9999999999999999
ZD      0.99 [!!!blad!!!]
NF      1,00

Dodawanie w pętli 0.1 powoduje zwiększanie błędu (0.1 baaardzo źle jest reprezentowane... po to są reprezentacje dziesiętne :) )
Myślę, że zabawa z liczbami zm. przec. wymaga trochę praktyki i testowania rozwiązań, ale jeśli to ucinanie liczb Tobie odpowiada to spoko :>

++
yyy, w kodzie powinno być jeszcze format + ZaokraglanieDouble, ale akurat takie obcięcie daje dla format() identyczny (zły) wynik co print()

0

Faktycznie... teraz problem jest w druga strone :/ Bez zaokraglen wyniki po zsumowaniu byly zawyzone... teraz sa zanizone bo ucialem za duzo... faktycznie blad jest BARDZO powazny :/ Nawet nie zauwazylem ze to jest obcinanie a nie zaokraglanie [rotfl] Pozostaje jedynie ktorys ze sposobow wyciskajacy wiecej potu z procka (o ktorych pisalismy) :]

0

oto krotkie podsumowanie moich dotychczasowych eksperymentow: MarcinEc - wynikiem funkcji ktora podales (z grubsza ujmujac) jest String czyli element gotowy do wyprowadzenia dla uzytkownika np. na ekran. Jesli jednak bedziesz chcial uzyc ja do dalszych obliczen to niestety musisz wykonac jeszcze parsowanie na Double aby znow uzyskac liczbe. Malo tego... zamiana na Stringa spowoduje zamiane kropki na przecinek wiec jeszcze dochodzi korekcja Stringa. Ostatecznie mamy wiec trzy rozne funkcje:

//===================================================
static public double Zaokragl_1 (double z)
{
  z=new BigDecimal(z).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
  return z;
}
//===================================================
static public String Zaokragl_2 (double d)
{
  NumberFormat nf = NumberFormat.getInstance();
  nf.setMaximumFractionDigits(2);
  nf.setMinimumFractionDigits(2);
  return nf.format(d);
}
//===================================================
static public double Zaokragl_3 (double d)
{
  NumberFormat nf = NumberFormat.getInstance();
  nf.setMaximumFractionDigits(2);
  nf.setMinimumFractionDigits(2);
  return Double.parseDouble((nf.format(d)).replaceAll(",", "."));
}
//===================================================

Z przeprowadzonych przeze mnie testow wynika ze predkosc dzialania jest rozna (to oczywiste). Test polegal na kilkakrotnym wywolaniu kazdej z wyzej wymienionych funkcji 1 milion razy (wyniki dla procesora Intel Pentium 2.4):
Zaokragl_1 - ok 12400 milisekund
Zaokragl_2 - ok 11440 milisekund
Zaokragl_3 - ok 17050 milisekund
Wniosek? Pierwsza jest najszybsza jesli chcemy uzyskac zaokraglana liczbe double, a druga jesli chcemy aby wynikiem byl String. :]

0

Mój ostatni post... chyba :)
Myślę, że kilka rzeczy pomieszało się w tym wątku. Otóż, wracając do pierwszego postu: 5 - 5.57 = -0.57

  1. W (teoretycznej) binarnej reprezentacji zmiennoprzecinkowej ta liczba 0.57 jest okresowa, czyli musiała by być zapisana na nieskończonej ilości bitów. Na komputerze liczba ta ma w sobie pewien błąd wynikający z tego, że musi być zapisana na skończonej liczbie bitów mantysy (a tak bardzo dokładnie jej reprezentacja powinna być nieskończona...). I to jest właściwość liczb double na komputerze. Natomiast drukowanie tej liczby ze zbyt dużą ilością miejsc powoduje pokazanie tego błędu na którejś dalekiej pozycji. Z tego wniosek, że nie należy przesadzać z ilością miejsc po przecinku :)

  2. Zaokrąglanie liczb... To zupełnie inna bajka :) To jest takie bezpośrednie ingerowanie w liczbę i zmiana jej wartości! 0.00158 może stać się 0.0016, ale to nie będzie w double 0.00158, tylko to będzie już nowa wartość 0.0016, a w obliczeniach chyba powinna być ta dokładniejsza? Myślę, że błąd jest mniejszy, gdy zostawimy doubla takiego jakim jest, niż użyjemy zaokrąglenia... [być może zależy to od obliczeń...?]

  3. Ta klasa BigDecimal jest przeznaczona do wykonywania obliczeń o zadanej precyzji, a nie do zaokrąglania liczb double :)

I teraz: zastanów się co chcesz osiągnąć drukować te liczby z dwoma miejscami po przecinku (NumberFormat), czy naprawdę zaokrąglać podczas obliczeń (w dół i zbierać te grosze :D ) ???

Tu masz kod zaokrąglania :) Prawie taki jak twój, tylko trzeba użyć round():
http://www.dickinson.edu/~braught/courses/cs132s01/classes/code/Rounding.src.html

0

To tez moj ostatni post w tej kwestii... chyba :]
Odpowiedzi (do tego co napisal MarcinEc)
1 + 2. Biore sobie kartke papieru i wykonuje na niej dzialanie 5 - 5.57 pisemnie jesli chcesz... wychodzi mi wprost = 0.57, w komputerze juz tak nie jest... Wniosek jest jeden... komputer to "kłamczuch" :/ A tak powaznie to oczywiscie MarcinEc masz racje ze wynika to ze sposobu zapisu liczby zmiennoprzecinkowej w pamieci komputera. Jednak w obliczeniach, gdy chodzi o kase to musze po kazdej operacji zaokraglac/zerowac mantyse/obcinac (jak kto sobie zyczy tak to sobie nazwie) to paskudztwo ktore mam na 20 miejscu po przecinku bo w pozniejszych obliczeniach moze mi przez to wyniknac blad.

  1. Mozliwe, nie wglebialem sie w to az tak bardzo :] Fakt jest taki ze chce miec zaokraglone (w sensie wyzerowania tej koncowki) i mam... zreszta jak w kazdym z wymienionych przypadkow, sprawdza sie znakomicie (choc czasy wykonania operacji sa rozne)

Co chce z tym robic? Potrzebne mi te liczby i do obliczen i do wyprowadzenia dla user'ow, wiec poki co uzywam obu bo w roznych przypadkach rozne sa potrzebne.

No i na koniec przelom... chyba, bo okazuje sie ze kod na tej stronie (ktara podal MarcinEc)
http://www.dickinson.edu/~brau[...]classes/code/Rounding.src.html

    public static double round(double val, int places) {
    	long factor = (long)Math.pow(10,places);
    	val = val * factor;
    	long tmp = Math.round(val);
   	return (double)tmp / factor;
        }

jest wrecz niesamowity! Wykonuje to ok 600ms !!!!!! [green] Wychodzi na to ze kod ten jest wydajniejszy o 2000% w porowaniu do tego co wszyscy z nas proponowali :]

0
axiomat napisał(a)

(...)Jednak w obliczeniach, gdy chodzi o kase to musze po kazdej operacji zaokraglac/zerowac mantyse/obcinac (jak kto sobie zyczy tak to sobie nazwie) to paskudztwo ktore mam na 20 miejscu po przecinku bo w pozniejszych obliczeniach moze mi przez to wyniknac blad.

NIE! Liczb double nie można używać do obliczeń pieniężnych! Stąd biorą się Twoje problemy z małymi wartościami na końcu liczby...
Znalazłem bardzo ciekawy wątek nt. pieniędzy (w Javie):
http://www.theserverside.com/patterns/thread.tss?thread_id=28063
Ciekawa może być klasa Fraction z http://sourceforge.net/projects/securecollect/ ??
W tym wątku jest zwrócona uwaga na pewną rzecz z 0.1: otóż, konstruując BigDecimal z double 0.1 popełniamy błąd, dlatego, że musi nastąpić konwersja ze źle reprezentowanej 0.1d na BigDecimal i powinno się użyć konstruktora ze Stringa "0.1" :)
Jeżeli cię to interesuje to radze dokładnie przeczytać. To nie jest prosty problem. Ciekawostka: jak podzielić 10,- złotych na 3 osoby bez utraty pieniędzy? :D Nie jestem bankowcem i do napisania programu obsługującego bankowość naprawdę potrzebował bym speca od bankowości... albo duużo musiał bym się dowiedzieć... :>

axiomat napisał(a)

Co chce z tym robic? Potrzebne mi te liczby i do obliczen i do wyprowadzenia dla user'ow, wiec poki co uzywam obu bo w roznych przypadkach rozne sa potrzebne.

Przy obliczeniach matematycznych (np. wartość funkcji) nawet nie próbuj tego zaokrąglać, bo i po co.
Wystarczy odpowiednio sformatować liczbę, którą pokażesz użytkownikowi (oczywiście możesz ją matematycznie zaokrąglić).
Uff... Powodzenia!

0

W wiekszosci tego co napisales to zgadzam sie z toba MarcinEc, ale mysle ze odrobine wyolbrzymiles problem...

  1. Double uzywam bo dane przechowywane sa w bazie danych... tam jest typ Double Precision, wiec mam je czytac rzutowac, obrabiac i znow zapisywac jako double? juz chyba lepiej zaokraglac/obcinac te koncowki ktore i tak sa nieistotne, a wynikaja wylacznie ze sposobu zapisu danych w komputerze. Ta ostatnia funkcja ktora jest wydajniejsza o 2000% w zupelnosci mnie zadowala, biorac pod uwage ze program ktory dotychczas wykonywal te operacje przez 21 godz, teraz robi to przez niecale 2 godz, to wynik jest w pelni satysfakcjonujacy :] po prostu nie ma sensu przepisywac calego systemu na nowy (co trwalo by z kilka miesiecy) kiedy juz osiagnelem zadowalajace rezultaty w tej jednej kwestii, choc oczywiscie system okazuje sie przestarzaly biorac pod uwage ze sa sposoby na inna reprezentacje danych monetarnych)

  2. Nie musze dzielic 10 zl na 3 osoby ;P dzieleniem zajmuje sie raczej ksiegowosc, ja wykonuje niemal wylacznie dodawanie i odejmowanie (wystarczy wyksztalcenie podstawowe [green]

Wniosek: Nasza debata dala w pelni zadowalajace rezultaty, nie wydaje mi sie aby mozna bylo zoptymalizowac funkcje zaokraglania bardziej niz ta w/w. Prawda jest jednak ze problemu zaokraglania koncowek w kwestii przeliczania kasy przy pomocy komputera nie mozna traktowac po macoszemu i jest to temat wciaz aktualny, w ktorym zawsze cos ciekawego mozna jeszcze dopisac i zmienic

0

tak w sumie jeśli chodzi o kwoty to najlepiej jest przejść z każdą z tych liczb na long (na przykład z dokładnością do dziesiątej części grosza) wykonywać później operacje na longach i sam wynik znów przekonwertować na double. Ale nie jestem pewien jakie to może rodzić problemy.
Pozdrawiam - erer

0

W obliczeniach finansowych najlepiej jest wykorzystać klasę BigDecimal. Ma ona nieograniczoną (prawie, ograniczenie to ilość dostępnej pamięci) dokładność ponieważ zamiast liczb wykorzystuje operacje na Stringach :)

Generalnie do drobniejszej zabawy wystarczy double i long :) do powazniejszej BigDecimal i BigInteger

0

Nie dość, że odgrzewacie wątek sprzed prawie dwóch lat, to jeszcze głupoty wypisujecie. Przeczytaliście chociaż posty? :/

0

nie wazne czy BigDecimal czy double, bo i tak tracimy precyzje lub zwiekszamy zlozonosc
jesli chodzi o zmienne "walutowe" to powinno sie trzymac w groszach,centach a userowi prezentowac tylko wartosc w zł

pozdrawiam

0

Dyskusja prowadzona w poprzednich postach była bardzo interesująca. Błąd liczb typu double (na 14,15 miejscu po przecinku) wynika z kodowania binarnego. Tylko że podobne programy pisane w języku REXX nie dają takich rezultatów. Ułożyłem sobie programik iteracyjny i w wynikach nie wyświetlały się dziwne cyfry na 15 miejscu po przecinku. Wyniki były takie, jakich się spodziewałem. Czy REXX inaczej "przetwarza" liczby?

0

@mr., możliwe. Samo przetwarzanie może opierać się na przykład na operacjach na tablicach bajtów lub też bitów. Języki ogólnego przeznaczenia są generalnie dość tępe jeśli chodzi o precyzję. Jak masz język specjalizowany to niektóre, kluczowe, funkcje języka pisane są w taki sposób, aby maksymalizować ich wydajność lub udostępniać nietypowe funkcjonalności.

0

A co jeśli musimy zaokrąglić liczbę 3.796459427293194E-24 ??
Ta metoda niestety nie działa.

0

eximus napisal:

jesli chodzi o zmienne "walutowe" to powinno sie trzymac w groszach,centach a userowi prezentowac tylko wartosc w zł

akurat sie nie zgadzam poniewaz to nic nie rozwiazuje - zakladasz ze grosz czy cent to jednostka niepodzielna, a ja tak sie sklada pisze system billingowy dla zagranicznego operatora sieci komorkowych ktory za 0.5mb danych sciagnietych grps zyczy sobie 170.2 eurocenta. jesli chcesz to dzielic przeliczac to cokolwiek bys nie zrobil to musisz sie babrac ze zmiennoprzecinkowymi

ja wiem tyle - pieniadze => BigDecimal i juz, i jak juz ktos wspomnial, stringowe konstruktory pozwalaja pominac niedokladnosci dougle, bo co z tego ze utworze BigDecimala,czyli "jedyna sluszna" klase w tym momencie, ale bedzie ona zaweirala blad z doubla?

0

@eximius, weto i to zdecydowane. W obliczeniach finansowych musisz zachować ogromną precyzję ponieważ niektóre kwoty podaje się co do setnej części grosza, na przykład notowania walut. Jeżeli będziesz trzymał wartości "prawie" całkowite to w trakcie obliczeń i zaokrągleń zaczną się dziać "kreatywna księgowość".

@zaurak001, metoda sobie poradzi wezmę jakiś z języków "laboratoryjnych" gdzie muszę mieć dużą precyzję (masa elektronu). Zresztą tu problem jest w sposobie zaokrąglania liczb w okolicach 1 i ich prezentacji.

@arczibald, BigDecimal z założenia nie powinien zawierać błędów. Jeżeli jesteś mocny to możesz spróbować w momencie wykrycia błędu napisać własne klasy. Zresztą działania podstawowe na bitach nie są takie trudne.

0

Koziolek, przeczytaj uwaznie - nie napisalem ze ta klasa ma bledy, to o co mi chodzilo to ze jak tworzysz ja z double ktory sam w sobie jest niedokladna reprezetnacja jakiejs liczby, to BigDecimal tez bedzie ten blad zawieral. Wykonaj ten kod:

package test;

import java.math.BigDecimal;

public class Test {

    public static void main(String[] args) throws Exception {
        double d = 0.1;
        BigDecimal bd = new BigDecimal(d);
        BigDecimal bd2 = new BigDecimal("0.1");
        System.out.println("double = " + bd + "\nstring = " + bd2);
    }

}

Moj wynik to:

double = 0.1000000000000000055511151231257827021181583404541015625
string = 0.1

Pozdro.

1 użytkowników online, w tym zalogowanych: 0, gości: 1