Spostamento delle cifre decimali in una doppia

Quindi ho un doppio set uguale a 1234, voglio spostare una cifra decimale per renderla 12.34

Quindi per farlo moltiplichiamo da 1 a 1234 due volte, un po ‘come questo

double x = 1234; for(int i=1;i<=2;i++) { x = x*.1; } System.out.println(x); 

Questo stamperà il risultato, “12.340000000000002”

C’è un modo, senza semplicemente formattarlo a due cifre decimali, per avere correttamente il doppio negozio 12.34?

Se si utilizza il double o il float , è necessario utilizzare l’arrotondamento o si aspettano di vedere alcuni errori di arrotondamento. Se non puoi farlo, usa BigDecimal .

Il problema è che 0.1 non è una rappresentazione esatta, e eseguendo il calcolo due volte, si sta aggravando quell’errore.

Tuttavia, 100 può essere rappresentato con precisione, quindi prova:

 double x = 1234; x /= 100; System.out.println(x); 

che stampa:

 12.34 

Funziona perché Double.toString(d) esegue una piccola quantità di arrotondamenti per tuo conto, ma non è molto. Se ti stai chiedendo come potrebbe apparire senza arrotondamento:

 System.out.println(new BigDecimal(0.1)); System.out.println(new BigDecimal(x)); 

stampe:

 0.100000000000000005551115123125782702118158340454101562 12.339999999999999857891452847979962825775146484375 

In breve, l’arrotondamento è inevitabile per le risposte sensate in virgola mobile, indipendentemente dal fatto che lo facciate esplicitamente o meno.


Nota: x / 100 e x * 0.01 non sono esattamente la stessa cosa quando si verifica un errore di arrotondamento. Questo perché l’errore di arrotondamento per la prima espressione dipende dai valori di x, mentre lo 0.01 nel secondo ha un errore di arrotondamento fisso.

 for(int i=0;i<200;i++) { double d1 = (double) i / 100; double d2 = i * 0.01; if (d1 != d2) System.out.println(d1 + " != "+d2); } 

stampe

 0.35 != 0.35000000000000003 0.41 != 0.41000000000000003 0.47 != 0.47000000000000003 0.57 != 0.5700000000000001 0.69 != 0.6900000000000001 0.7 != 0.7000000000000001 0.82 != 0.8200000000000001 0.83 != 0.8300000000000001 0.94 != 0.9400000000000001 0.95 != 0.9500000000000001 1.13 != 1.1300000000000001 1.14 != 1.1400000000000001 1.15 != 1.1500000000000001 1.38 != 1.3800000000000001 1.39 != 1.3900000000000001 1.4 != 1.4000000000000001 1.63 != 1.6300000000000001 1.64 != 1.6400000000000001 1.65 != 1.6500000000000001 1.66 != 1.6600000000000001 1.88 != 1.8800000000000001 1.89 != 1.8900000000000001 1.9 != 1.9000000000000001 1.91 != 1.9100000000000001 

No: se si desidera memorizzare accuratamente i valori decimali, utilizzare BigDecimal . double semplicemente non può rappresentare esattamente un numero come 0.1, non più di quanto si possa scrivere il valore di un terzo esattamente con un numero finito di cifre decimali.

se è solo formattazione, prova printf

 double x = 1234; for(int i=1;i<=2;i++) { x = x*.1; } System.out.printf("%.2f",x); 

produzione

 12.34 

Nel software finanziario è comune usare interi per centesimi. A scuola, ci è stato insegnato come usare il punto fisso invece di fluttuare, ma di solito è un potere di due. Memorizzare i penny in numeri interi potrebbe anche essere chiamato “punto fisso”.

 int i=1234; printf("%d.%02d\r\n",i/100,i%100); 

In class, ci è stato chiesto in generale quali numeri possono essere esattamente rappresentati in una base.

Per base=p1^n1*p2^n2 … puoi rappresentare qualsiasi N dove N = n * p1 ^ m1 * p2 ^ m2.

Sia base=14=2^1*7^1 … puoi rappresentare 1/7 1/14 1/28 1/49 ma non 1/3

Conosco il software finanziario: ho convertito i rapporti finanziari di Ticketmaster da VAX asm a PASCAL. Avevano il loro formatln () con i codici per pochi centesimi. Il motivo della conversione era che gli interi a 32 bit non erano più sufficienti. +/- 2 miliardi di penny è di $ 20 milioni e che è traboccato per la Coppa del Mondo o le Olimpiadi, ho dimenticato.

Ho giurato segretezza. Oh bene. In ambito accademico, se è bello pubblichi; nell’industria, la tenga segreta.

puoi provare la rappresentazione del numero intero

 int i =1234; int q = i /100; int r = i % 100; System.out.printf("%d.%02d",q, r); 

Ciò è causato dal modo in cui i computer memorizzano i numeri in virgola mobile. Non lo fanno esattamente. Come programmatore, dovresti leggere questa guida in virgola mobile per familiarizzare con le prove e le tribolazioni della gestione dei numeri in virgola mobile.

Divertente che numerosi post menzionino l’utilizzo di BigDecimal ma nessuno si preoccupa di dare la risposta corretta basata su BigDecimal? Perché anche con BigDecimal, puoi ancora sbagliare, come dimostrato da questo codice

 String numstr = "1234"; System.out.println(new BigDecimal(numstr).movePointLeft(2)); System.out.println(new BigDecimal(numstr).multiply(new BigDecimal(0.01))); System.out.println(new BigDecimal(numstr).multiply(new BigDecimal("0.01"))); 

Fornisce questo risultato

 12.34 12.34000000000000025687785232264559454051777720451354980468750 12.34 

Il costruttore BigDecimal menziona specificamente che è meglio utilizzare il costruttore di stringhe rispetto a un costruttore di numeri. La massima precisione è influenzata anche dal MathContext opzionale.

Secondo BigDecimal Javadoc è ansible creare un BigDecimal che è esattamente uguale a 0.1, a condizione che si usi il costruttore String.

Si C’è. Con ogni doppia operazione si può perdere la precisione, ma la quantità di precisione varia per ogni operazione e può essere ridotta al minimo scegliendo la giusta sequenza di operazioni. Ad esempio, quando si moltiplica l’insieme di numeri, è meglio ordinare l’esponente prima di moltiplicarlo.

Qualsiasi libro decente sul numero di crunch descrive questo. Ad esempio: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

E per rispondere alla tua domanda:

Usa divide invece di moltiplicare, in questo modo ottieni il risultato corretto.

 double x = 1234; for(int i=1;i<=2;i++) { x = x / 10.0; } System.out.println(x); 

No, poiché i tipi di virgola mobile Java (in effetti tutti i tipi a virgola mobile) rappresentano un compromesso tra dimensioni e precisione. Mentre sono molto utili per molte attività, se hai bisogno di precisione arbitraria, dovresti usare BigDecimal .