Vai al contenuto

Qualità Horo


sirtao

Messaggi raccomandati

java.

JDK 1.6.0-17 su Windows(appena sono a casa testo su linux)

public class Primo{

      public static void main(String[] argv){

             //Variables
             int       varInteger=10;
             double    varDoppio=3.14;
             varDoppio=varInteger-varDoppio;
             System.out.print(varDoppio);
      }
}

 

qualcuno mi spiega perche' esce fuori 6.859999999999999 ?

ho provato a cambiare i valori, ma viene fuori SOLO con 10 e 3.14(se sia 10 che 3.14 sono negativi, viene -6.859999999999999)

Modificato da sirtao
Link al commento
Condividi su altri siti

A cambiarlo in Double, stesso identico problema. Anche se invece di 10 metto 10.0 o 10.00.

System.out.print(10-3.14) mi da' lo stesso risultato.

idem System.out.print(10.0-3.14) e System.out.print(10.00-3.14)

 

 

 

la cosa ha sempre meno senso... che è un easter egg che non da' il risultato corretto(perche' e' SBAGLIATO) se si sottrae 3,14 a 10?

Link al commento
Condividi su altri siti

Non ricordo più molto di Java, quindi non mi ricordo se abbia o meno il concetto di format string o una cosa del genere, nè in che modo stampi un numero reale come default. Il tuo problema è che non arrotonda solo per quella particolare somma (o sottrazione) verso un più leggibile 6.86, oppure non ti gusta che il risultato appaia "sbagliato" leggendo tutti i decimali?

No, perchè la conversione da base 10 a floating point base 2 introduce molto spesso degli errori di troncamento (per esempio 0.1 è periodico in base 2...) e dunque se vai a leggere tutta la precisione del numero quasi sempre i risultati di un calcolo in virgola mobile si discostano leggermente dal risultato algebrico. Se poi è un calcolo iterativo puoi perfino avere un errore che diverge se scegli male l'algoritmo, e un risultato finale del tutto insensato: buona parte dei corsi di analisi numerica si occupa proprio di questo problema.

 

E' il motivo per cui l'operatore "uguaglianza" fra due real non si deve usare mai, ma va sostituito da una sottrazione seguita dal confronto con un epsilon scelto sufficientemente piccolo a seconda dell'applicazione...

 

Ah, il metodo di arrotondamento indicato nel link di formatted_brain può anche funzionare, ma sicuramente è lento come la fame e non usabile per altro che l'output a schermo (e anche in quel caso, devono di certo esserci sistemi migliori)

Modificato da werner
Link al commento
Condividi su altri siti

Non ricordo più molto di Java, quindi non mi ricordo se abbia o meno il concetto di format string o una cosa del genere, nè in che modo stampi un numero reale come default. Il tuo problema è che non arrotonda solo per quella particolare somma (o sottrazione) verso un più leggibile 6.86, oppure non ti gusta che il risultato appaia "sbagliato" leggendo tutti i decimali?

Direi che il problema è che dovrebbe uscire 16.86 ^^

 

E' il motivo per cui l'operatore "uguaglianza" fra due real non si deve usare mai, ma va sostituito da una sottrazione seguita dal confronto con un epsilon scelto sufficientemente piccolo a seconda dell'applicazione...

 

Ah, il metodo di arrotondamento indicato nel link di formatted_brain può anche funzionare, ma sicuramente è lento come la fame e non usabile per altro che l'output a schermo (e anche in quel caso, devono di certo esserci sistemi migliori)

Ok, la prima cosa la diamo per buona, direi che chi ha un po' di esperienza già lo sa, però quel risultato lì è sbagliato veramente di tanto =_=

Link al commento
Condividi su altri siti

Non ricordo più molto di Java, quindi non mi ricordo se abbia o meno il concetto di format string o una cosa del genere, nè in che modo stampi un numero reale come default. Il tuo problema è che non arrotonda solo per quella particolare somma (o sottrazione) verso un più leggibile 6.86, oppure non ti gusta che il risultato appaia "sbagliato" leggendo tutti i decimali?

Direi che il problema è che dovrebbe uscire 16.86 ^^

 

Secondo me ha sbagliato a trascrivere il codice, 20 è citato solo lì dentro, da tutte le altre parti (incluso il testo subito sotto il codice) sirtao dice 10 :)

Link al commento
Condividi su altri siti

si, ho sbagliato a copiare una delle varie prove con valori diversi per vedere se faceva sempre quell'errore(ora ho corretto il code)... ma comunque e' un errorone.

francamente, mi par strano che una semplice sottrazione finisca con un errore del genere... cioe', non sono un ingegniere, ma un errore del genere io lo vedo come da uccidere i debugger maledendoli fino alla 10-3.14ima generazione....

Link al commento
Condividi su altri siti

francamente, mi par strano che una semplice sottrazione finisca con un errore del genere... cioe', non sono un ingegniere, ma un errore del genere io lo vedo come da uccidere i debugger maledendoli fino alla 10-3.14ima generazione....

Invece è normalissimo, fidati ;) E' che ormai la gente si fida così tanto dei computer che non te lo insegnano più se non all'università. A me l'hanno spiegato in prima liceo, ma il mio prof di informatica era un figo ^^

 

Il problema è che i numeri floating point non hanno nessuna corrispondenza diretta con l'aritmetica decimale: sono dei numeri in notazione scientifica in base due, a dimensione fissa. Fissa e non molto generosa, in singola precisione: un float a 32 bit ne dedica 8 all'esponente (da 2^-128 a 2^+127), uno al segno e i restanti 23 alla mantissa, cioè alle cifre significative. 23 cifre binarie (più una in realtà, recuperata rinormalizzando l'esponente, ma questo è un dettaglio) corrispondono a 7 cifre decimali. Dunque puoi scrivere all'incirca tutti i numeri del tipo A,BCDEFG x 10^N, con N compreso tra -37 e +37.

 

Ne segue che un miliardo più tre, in singola precisione, fa.... un miliardo. (1,000000 x 10^9 + 3,000000 x 10^0 in sette cifre non ci sta....)

 

Ti sembra che faccia schifo? Sì, in effetti lo fa; i single precision sono sempre stati un tipo di dato un po' del menga. Non per caso il "mio" vecchio, carissimo Turbo Pascal 7 usava dei "real" da 48 bit ;) E adesso, con l'esuberanza di memoria che c'è, credo che si tenda quasi sempre a usare direttamente i double precision e via.

Con i double non hai quasi mai problemi di precisione (52 bit di mantissa = 16 cifre), ma ti resta un problema ineliminabile: l'arrotondamento dei risultati intermedi. Quando fai un'operazione, tutti i bit che non ci stanno nella mantissa devono essere troncati. E molti numeri che in decimale hanno una scrittura banale, in binario sono periodici. Dunque NON POSSONO essere rappresentati esattamente... ecco perchè prima ho scritto "all'incirca".

Modificato da werner
Link al commento
Condividi su altri siti

capito, la solita roba che avrebbe dovuto dirmi quella balorda della prof di Informatica, ma data la sua ignoranza non ha mai accennato.

 

Dovro' farlo notare anche al corso, pero', visto che quindi questo tipo di problema potrebbe apparire spesso.

 

 

ma comunque non capisco come questo problema possa applicarsi a una SOTTRAZIONE A DUE DECIMALI...

Link al commento
Condividi su altri siti

Con i double non hai quasi mai problemi di precisione (52 bit di mantissa = 16 cifre), ma ti resta un problema ineliminabile: l'arrotondamento dei risultati intermedi.Quando fai un'operazione, tutti i bit che non ci stanno nella mantissa devono essere troncati. E molti numeri che in decimale hanno una scrittura banale, in binario sono periodici. Dunque NON POSSONO essere rappresentati esattamente...

:sisi:

Geekismi a parte, quel codice ha un'utilità o è un semplice esercizio di programmazione? Perchè il risultato lo si arrotonda anche abbastanza facilmente, ma dipende da cosa ci devi fare (e sinceramente dubito che il problema si presenti SOLO con 10-3.14... Però che culo a beccarli così al primo colpo :pfff: )

Link al commento
Condividi su altri siti

ma comunque non capisco come questo problema possa applicarsi a una SOTTRAZIONE A DUE DECIMALI...

Perchè quella sottrazione è a due decimali in... decimale, ma NON in binario ;)

 

Gli unici numeri razionali che NON sono periodici in binario sono quelli che corrispondono a una frazione del tipo a/2^b; nel tuo caso, 10 lo puoi scrivere in quel modo[*], ma 314/100 no: ecco dunque che 3,14 non può essere memorizzato perfettamente.

Il vero problema è che tu stai chiedendo al computer più precisione di quella che hai bisogno, arrivando a superare quella che ti può dare: anche con un umilissimo float, l'errore se c'è si presenta al settimo decimale, con un double al quindicesimo. Tu hai davvero bisogno di così tanti decimali? Ne dubito.

 

Ti sei accorto del problema perchè hai fatto stampare il risultato come 6.859999999999999, con SEDICI cifre. Se ne avessi chieste "solo" dodici, il numero sarebbe stato arrotondato e il computer ti avrebbe tranquillamente restituito 6,86.

 

Quindi se fai dei calcoli semplici non ti devi preoccupare, basta scegliere un numero sensato di decimali nelle stampate a video. I guai seri possono arrivare se devi scrivere dei cicli che rimasticano milioni di volte gli stessi numeri floating point, dove gli errori potrebbero sommarsi fra loro a ogni giro. La soluzione a questo genere di problemi, se si presentano, non è affatto banale e va valutata caso per caso, con l'aiuto dei molti tomi di analisi numerica che sono stati scritti nel corso degli anni. Comunque non è frequentissimo nemmeno in ambito scientifico, quindi non credo che incontrerai situazioni simili, visto che per fare matematica userai probabilmente librerie scritte da altri che a queste grane ci hanno già pensato ;)

 

Ah, ultima cosa: tutto questo è il motivo per cui le applicazioni finanziarie NON usano numeri in virgola mobile, ma grossi interi a 64 bit.

 

 

 

 

[*] Posso dirti al volo che quel numero sarà memorizzato in hardware come 8 x (1 + 1/4), dunque esponente 3, mantissa (1)010000000000..... (il primo 1 è sottinteso.) La miglior rappresentazione di 3,14 se la vuoi te la trovi da solo con questa applet :P

http://www.ajdesigner.com/fl_ieee_754_word/ieee_32_bit_word.php

Modificato da werner
Link al commento
Condividi su altri siti

Crea un account o accedi per lasciare un commento

Devi essere un utente registrato per poter lasciare un commento

Crea un account

Iscriviti per un nuovo account nella nostra comunità. È facile!

Registra un nuovo account

Accedi

Sei già un account? Accedi da qui.

Accedi Ora
  • Navigazione Recente   0 utenti

    Nessun utente registrato visualizza questa pagina.

×
×
  • Crea Nuovo...

Informazione Importante

Procedendo oltre nell'uso di questo sito, accetti i nostri Termini Di Utilizzo