|
|
Pubblicato su 07/04/2015 14:53:05
|
|
|

In Java sono fornite classi di operazione per numeri grandi, ovvero la classe java.math.BinInteger e la classe java.math.BigDecimal. Queste due classi sono utilizzate per il calcolo ad alta precisione, con la classe BigInteger che è la classe di elaborazione per numeri interi grandi e la classe BigDecimal che è la classe di elaborazione per numeri grandi e piccoli. Di seguito presentiamo la classe BigDecimal: L'implementazione di BigDecimal sfrutta BigInteiro, tranne che BigDecimal aggiunge il concetto di decimali. I dati generali float e di doppio tipo possono essere utilizzati solo per calcoli scientifici o di ingegneria, perché nell'informatica commerciale l'accuratezza numerica richiesta è relativamente alta, quindi si utilizza la classe java.math.BigDecimal, che supporta qualsiasi precisione dei punti fissi e può essere utilizzata per calcolare con precisione i valori di valuta. Di seguito presenteremo brevemente il suo utilizzo con esempi
java.math.BigDecimal
Oggi ho scritto un programma sulla conversione binaria e decimale con riferimento al libro di testo, e l'algoritmo del programma non è difficile, ma dopo aver scritto ho scoperto che, sia da 2 a 10 che da 10 a 2, non è una buona conversione per numeri superiori a 2,1 miliardi, cioè superiori all'intervallo intero. diventerà 0. I libri di riferimento hanno scoperto che l'uso di BigInteger risolve questo problema. Così ho cercato il JDK, l'ho testato più volte e alla fine l'ho scritto con successo! L'esperienza d'uso è la seguente:
1. BigInteger appartiene a java.math.BigInteger, quindi importa questa classe prima di ogni utilizzo. A volte dimenticavo di importare all'inizio, quindi il prompt non si trovava nel prompt costante.
2. Esistono molti metodi costruttivi, ma ora sono occasionalmente utilizzati: BigInteger (String val) Converti la rappresentazione decimale della stringa BigInteger in BigInteger. BigInteger (String val, int radix) Converte la rappresentazione della stringa del BigInteger per la cardinalità specificata nel BigInteger. Per convertire 2 di tipo int in tipo BigNumber, scrivi BigInteger due = nuovo BigInteger ("2"); Nota 2: le virgolette doppie non possono essere omesse
3. La classe BigInteger simula tutte le operazioni matematiche di tipo int, come add()=="+", divide()=="-", ecc., ma si noti che il suo contenuto non può essere utilizzato direttamente per operazioni matematiche durante l'esecuzione di operazioni matematiche, e deve utilizzare i suoi metodi interni. E il suo operando deve essere anch'esso di tipo BigInteger. Ad esempio: two.add(2) è un'operazione errata perché 2 non diventa un tipo BigEnter.
4. Quando vuoi produrre i risultati del calcolo, dovresti usare il metodo .toString per convertirlo in una stringa decimale, come dettagliato di seguito: Stringa a Stringa() Restituisce la rappresentazione decimale della stringa di questo BigIntero. Metodo di output: System.out.print(two.toString());
5. Spiega le tre funzioni utilizzate. BigInteger remainder(BigInteger val) Restituisce un BigInteger con un valore di (questo % val). Negazione BigInteger () BigInteger restituisce un valore di (-this). int compareTo(BigInteger val) Confronta questo BigInteger con il BigInteger specificato. Resti usati per trovare il resto. la negazione trasforma l'operando nell'opposto. Il confronto viene spiegato in dettaglio come segue: confronteTo
public int compareTo(BigInteger val)
Confronta questo BigInteger con il BigInteger specificato. Questo metodo è preferito per ciascuno dei sei operatori di confronto booleani (<, ==, >, >=, !=, <=). L'affermazione suggerita per eseguire questi confronti è: (x.compareTo(y) <op> 0), dove è <op> uno dei sei operatori di confronto.
Specificatore: interfaccia<BigInteger> Comparabile
Parametri: val - Il BigInteger che confronta questo BigInteger con esso. Indietro:
Titolo Implementazione di calcoli precisi di numeri in virgola mobile in Java Modifica Astile (originale) Parole chiave Java calcolo preciso dei numeri in virgola mobile
Domanda posta: Cosa vedremmo se compilassimo ed eseguissimo il seguente programma? classe pubblica Test{ public static void main(String args[]){ System.out.println(0.05+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(123.3/100); } };
Hai letto bene! Il risultato è, in effetti 0.060000000000000005 0.5800000000000001 401.49999999999994 1.2329999999999999
Semplici tipi float e double in Java non possono essere gestiti. Questo problema non si riscontra solo in Java, ma anche in molti altri linguaggi di programmazione. Nella maggior parte dei casi, i calcoli sono accurati, ma puoi provare ancora qualche volta (puoi fare un loop) a provare errori come quello sopra. Ora finalmente capisco perché esiste un codice BCD. Questo problema è piuttosto serio: se hai 9,99999999999999999999 yuan, il tuo computer non penserà che tu possa comprare 10 yuan di beni. Alcuni linguaggi di programmazione forniscono tipi di valuta specializzati per gestire questa situazione, ma Java no. Ora vediamo come risolvere questa situazione.
Arrotondamento La nostra prima reazione è fare il rounding. Il metodo del round nella classe di Matematica non può essere impostato per mantenere pochi decimali, possiamo fare solo questo (mantenere due punti): Doppio round pubblico(valore doppio){ return Math.round(value*100)/100.0; }
Purtroppo, il codice sopra non funziona, passando la 4.015 a questo metodo restituirà la 4.01 invece della 4.02, come abbiamo visto sopra 4.015*100=401.49999999999994 Pertanto, se vogliamo fare un arrotondamento accurato, non possiamo usare tipi semplici per eseguire operazioni Nemmeno java.text.DecimalFormat risolve questo problema: System.out.println(nuovo java.text.DecimalFormat("0.00").format(4.025)); La potenza è 4,02
BigDecimal Questo principio è menzionato anche nel libro "Effective Java", float e double possono essere usati solo per calcoli scientifici o ingegneristici, e nel business computing dobbiamo usare java.math.BigDecimal. Ci sono 4 modi per costruire BigDecimal, non ci interessano i due che sono fatti con BigInteger, quindi ce ne sono altri due, che sono: BigDecimal (doppia valle) Traduce un doppio in un BigDecimal. BigDecimal(val stringa) Traduce la rappresentanza di stringhe di un BigDecimal in una BigDecimal.
L'API è brevemente descritta ed è solitamente più facile da usare. Potremmo usarlo senza nemmeno pensarci, qual è il problema? Quando qualcosa andava storto, scoprii che esisteva un paragrafo del genere nella descrizione dettagliata di quale dei metodi sopra sopra fosse sufficiente: Nota: i risultati di questo costruttore possono essere in parte imprevedibili. Si potrebbe supporre che il nuovo BigDecimal(.1) sia esattamente uguale a .1, ma in realtà è uguale a .1000000000000000055511151231257827021181583404541015625. Questo perché 0.1 non può essere rappresentato esattamente come un doppio (o, peraltro, come una frazione binaria di qualsiasi lunghezza finita). Quindi, il valore lungo che viene passato al costruttore non è esattamente uguale a 0.1, prescindibili delle apparenze. Il costruttore (stringa), invece, è perfettamente prevedibile: il nuovo BigDecimal(".1") è esattamente uguale a .1, come ci si aspetterebbe. Pertanto, generalmente si raccomanda di usare il costruttore (String) in preferenza a questo.
Si scopre che, se dobbiamo calcolare con precisione, dobbiamo usare String per creare BigDecimal! L'esempio nel libro Effective Java usa String per creare BigDecimal, ma il libro non enfatizza questo aspetto, il che potrebbe essere un piccolo errore.
Soluzione Ora che abbiamo risolto questo problema, il principio è usare BigDecimal e assicurarsi di usare String. Ma immagina che vogliamo fare un'operazione di addizione, dobbiamo prima convertire due numeri in virgola mobile in String, poi creare un BigDecimal, chiamare il metodo di somma su uno di essi, passare l'altro come argomento e infine convertire il risultato dell'operazione (BigDecimal) in un numero in virgola mobile. Riesci a sopportare un processo così noioso? Di seguito forniamo una classe di strumenti Arith per semplificare l'operazione. Offre i seguenti metodi statici, tra cui addizione, sottrazione, moltiplicazione e divisione, e arrotondamento: Doppia aggiunta statica pubblica (doppia v1, doppia v2) Public static double sub (double v1, double v2) Statico pubblico doppio MUL (doppio v1, doppio v2) Doppia div statica pubblica (doppia v1, doppia v2) Doppia div statica pubblica (doppia v1, doppia v2, scala INT) Doppio round statico pubblico (doppio v, scala INT)
Appendice
File sorgente Arith.java:
importa java.math.BigDecimal; /** * Poiché i tipi semplici di Java non possono eseguire con precisione operazioni in virgola mobile, questa classe di strumento fornisce multe * Operazioni esatte in virgola mobile, inclusi addizione, sottrazione, moltiplicazione, divisione e arrotondamento. */
classe pubblica Arith{
Accuratezza predefinita delle operazioni di divisione Privato Static Final Int DEF_DIV_SCALE = 10;
Questa classe non può essere istanziata privato Arith(){ }
/** * Fornisce operazioni di addizione precise. * @param viene aggiunta la v1 * @param aggiunta v2 * @return La somma dei due parametri */
pubblica statica doppia add(doppia v1,doppia v2){ BigDecimal b1 = nuovo BigDecimal(Double.toString(v1)); BigDecimal b2 = nuovo BigDecimal(Double.toString(v2)); return b1.add(b2).doubleValue(); }
/** * Fornisce operazioni di sottrazione precise. * @param v1 viene sottratto * @param v2 meno * @return La differenza tra i due parametri */
pubblico statico doppio sub(doppio v1,doppio v2){ BigDecimal b1 = nuovo BigDecimal(Double.toString(v1)); BigDecimal b2 = nuovo BigDecimal(Double.toString(v2)); return b1.subtract(b2).doubleValue(); }
/** * Fornisce operazioni di moltiplicazione precise. * @param v1 viene moltiplicato * @param moltiplicatore v2 * @return Il prodotto dei due parametri */
pubblico statico doppio mul(doppio v1,doppio v2){ BigDecimal b1 = nuovo BigDecimal(Double.toString(v1)); BigDecimal b2 = nuovo BigDecimal(Double.toString(v2)); return b1.multiply(b2).doubleValue(); }
/** * Fornisce operazioni di divisione (relativamente) accurate, quando si verifica una divisione inesauribile * 10 decimali e le cifre successive sono arrotondate. * @param v1 è diviso * @param divisore v2 * @return Il quoziente dei due parametri */
public static double div(double v1,double v2){ return div(v1,v2,DEF_DIV_SCALE); }
/** * Fornisce operazioni di divisione (relativamente) accurate. Quando si verifica una situazione inesauribile, essa viene indicata dal parametro di scala * Determina l'accuratezza e i numeri dopo saranno arrotondati. * @param v1 è diviso * @param divisore v2 * @param scala indica che deve essere accurata fino a pochi decimali. * @return Il quoziente dei due parametri */
Public static double div(double v1,double v2,int scale){ se(scale<0){ lancia nuova IllegalArgumentException( "La scala deve essere un intero positivo o zero"); } BigDecimal b1 = nuovo BigDecimal(Double.toString(v1)); BigDecimal b2 = nuovo BigDecimal(Double.toString(v2)); return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); }
/** * Fornisce un arrotondamento decimale preciso. * @param v richiede l'arrotondamento dei numeri * @param scala è riservata dopo il punto decimale * @return Risultati arrotondati */
Doppio round statico pubblico (doppio v,int scala){ se(scale<0){ lancia nuova IllegalArgumentException( "La scala deve essere un intero positivo o zero"); } BigDecimal b = nuovo BigDecimal(Double.toString(v)); BigDecimal uno = nuovo BigDecimal("1"); return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); } }; |
Precedente:È meglio non impostare una stringa con significato come chiave primariaProssimo:Differenze e connessioni tra JDK, JRE, JVM
|