Gå til innhold

long -> double -> long, tap av presisjon?


Anbefalte innlegg

Noen som kan svar meg på om dette faktisk er helt trygt?

Har testet dette og det ser ut til å fungere helt fint, men føler meg ike helt trygg på den double saken.

 

long along = System.currentTimeMillis();

double adouble = (double)along;

System.out.println(along +"\n" + adouble + "\n" + (long)adouble );

 

Måten dette skal brukes på er å sende tiden(long) via en metode som skal ha double, for så å konventere tilbake til long for å få ut tiden internt (ja det *må* gjøres slik)

Lenke til kommentar
Videoannonse
Annonse

long->double->long kan være til tap av presisjon ja.

 

Istedetfor f.eks 3000 så får du kanskje 2999,999999999999999999999

 

På den andre siden så blir jo 2999,999999999999999999999 gjort om til 3000 når du gjør om til long igjen.

 

Hvis du skal jobbe med noe som ikke tåler presisjonstap og inneholder komma så bør man bruke BigDecimal klassen.

Endret av blackbrrd
Lenke til kommentar

Noe som ikke er spes relevant når du driver å gjør om fra long til double og long igjen.. det blir fort avvik...

 

Det er en grunn til at man ikke burde sammenligne double med ==, men heller sjekke hvor stor forskjellen er og sette en terskel.

Endret av blackbrrd
Lenke til kommentar
Noe som ikke er spes relevant når du driver å gjør om fra long til double og long igjen.. det blir fort avvik...

 

Det er en grunn til at man ikke burde sammenligne double med ==, men heller sjekke hvor stor forskjellen er og sette en terskel.

5433099[/snapback]

Jo, det er i høyeste grad relevant. Siden en long har en preisjon på 64 binære siffer, altså mister alt over 52 siffer av en long når du går om double (hele 12 siffer i worst case med tall < 2^63), når du tar et heltall om en double får du tallet tilbake innenfor 1/10^15

Endret av MailMan13
Lenke til kommentar

double test = 3.140000d;

test += 1d;

System.out.println(""+test);

if(test>4.140000000d) {

System.out.println("joda, ble litt større der gitt");

}

 

Gir hos meg resultatet:

4.140000000000001

joda, ble litt større der gitt

 

 

skjønner du nå hva jeg snakker om? :)

Endret av blackbrrd
Lenke til kommentar

Hvis du ser liiiitttt nærmere på det jeg viser her, så ser du at jeg illustrerer hvorfor du ikke kan bruke == operatoren sammen med double.

 

Hvis du legger sammen mange double'r så kan du tilslutt få feil i ikke bare det 15. sifferet, men også det 14 sifferet.. og da kan du få feil i det 13. sifferet, etc... (for å få feil i det 14 sifferet må du minst ha lagt sammen 10 doubles, for å få feil i det 13. sifferet må du minst ha lagt sammen 100 doubles, etc)

 

Poeng #2 som ser ut til å ha gått deg hus forbi er at hvis du har en double og legger den sammen med en annen double og så skriver den ut så kan du ende opp med et resultat som ikke er det man forventer. Istedet for å få 3.14 får du plutselig 3.140000000000001, som vist ovenfor.

 

Poeng #3 La oss si at istedetfor å få et tall som var 0,000000000000001 for mye hadde fått ett som var 0,000000000000001 for lite. Hvis du da gjør om f.eks 2,999999999999999d til en long får du 2, noe som blir HELT FEIL.

 

Eksempel:

double d = 2.99999999999999d;

System.out.println(""+d);

long l = (long)d;

System.out.println(""+l);

 

Resultat:

2.99999999999999

2

 

Poenget mitt er at når du gjør om fra double til long, eller fra double til String så må man tenke seg godt om*, ellers får man et helt annet resultat enn man vil.

 

*Man må bruke Math.round, eller NumberFormatter (som jeg ikke gidder å vise her)

 

Eksempel:

double d = 2.99999999999999d;

System.out.println(""+d);

long l = (long)d;

System.out.println(""+l);

long math = Math.round(d);

System.out.println(""+math);

 

Resultat:

2.99999999999999

2

3

Endret av blackbrrd
Lenke til kommentar
mange ting

Jeg har ikke motsagt eller prøvd å motsi noe av det du sier her, alle eksemplene dine viser variasjoner som er mindre enn 1/10^15 som er innenfor det man kan forvente og at man ikke skal bruke == er jeg fullstendig klar over. Jeg prøvde bare å si hvorfor man får variasjoner og hvor store de blir og derfor er størrelsen på et flyttalls signifikand høyst relevant. Skjønner ikke hvorfor du mener det er feil.

Endret av MailMan13
Lenke til kommentar

Problemet her er at Pingle spør:

Måten dette skal brukes på er å sende tiden(long) via en metode som skal ha double, for så å konventere tilbake til long for å få ut tiden internt (ja det *må* gjøres slik)

 

..og lurer på om det kan bli noen problemer... du sier, du får i verste fall feil i det 15. sifferet etter komma. Det er korrekt, men ikke helt relevant.

 

Pingle må nemlig ta hensyn til at det kan ha skjedd avrundingsfeil underveis og må derfor bruke Math.round(double) når han gjør om fra double til long.

 

Som du sier:

Jo, det er i høyeste grad relevant. Siden en long har en preisjon på 64 binære siffer, altså mister alt over 52 siffer av en long når du går om double (hele 12 siffer i worst case med tall < 2^63), når du tar et heltall om en double får du tallet tilbake innenfor 1/10^15

 

Dette er vel og bra, helt til du skal gjøre om fra double til long og det er en feil i det 15. sifferet bak komma og du bruker casting for å gjøre om, som er kjappt gjort å gjøre.

 

Da kan du plutselig få 2 istedetfor 3 som illustrert tidligere.

 

Poenget mitt er at du bagatiliserer avrundingsfeil i double, mens det i dette spesifikke tilfellet er høyst relevant.

 

Det kan godt tenkes at du hadde brukt f.eks Math.round(double) hvis det var du som programmerte, men jeg er ikke sikker på om Pingle hadde gjort det, jeg tenker han f.eks ikke var helt klar over trunkeringsproblematikken med bruk av casting fra double til long.

Endret av blackbrrd
Lenke til kommentar

Det er irrelevant hvor lite avvik du kan få ved bruk av double når du kan få et signifikant avvik når du gjør om fra double til long...

 

Helt enig, du har ikke gitt noen anbefalinger, rettet opp det i teksten min ;)

 

Hovedpoenget med tråden er jo om det er trygt å gjøre om fra long->double->long, noe det ikke nødvendigvis er og det kommer på ingen måte klart fram i postene dine ;)

Endret av blackbrrd
Lenke til kommentar
Det er irrelevant hvor lite avvik du kan få ved bruk av double når du kan få et signifikant avvik når du gjør om fra double til long...

 

Helt enig, du har ikke gitt noen anbefalinger, rettet opp det i teksten min ;)

 

Hovedpoenget med tråden er jo om det er trygt å gjøre om fra long->double->long, noe det ikke nødvendigvis er og det kommer på ingen måte klart fram i postene dine ;)

5436223[/snapback]

Bruker man ikke Math.round til omgjøringen, men bare kaster om har man ikke gjort noen avrunding, da kan det skje rare ting ja, det er jeg helt enig i.

Lenke til kommentar

Grunnen til at jeg terpet på det her er at jeg og en kompis begge har klønet det til med double's og det er veldig irriterende :p

 

[offtopic]

Litt interessant.. hvis man jobber med penger som gjerne skal ha to siginifikante siffer bak komma.. så må man legge sammen 10^13 doubles før man muligens får feil.. ;)

 

Norges oljefond er til sammenligning på litt mer enn 10^12 kr...

 

[/offtopic]

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...