Programovanie

Upozornenie: V jazyku Java zdvojnásobte hodnotu BigDecimal

Kombinácia veľkej celosvetovej vývojárskej základne Javy a ľahko dostupnej dokumentácie API online viedla k všeobecne dôkladnej a presnej dokumentácii rozhrania Java SE API. Stále existujú zákruty, ktoré nemusia byť také dôkladné alebo presné, ako by si človek prial, ale dokumentácia API je všeobecne celkom dobrá, čo sa týka dôkladnosti aj presnosti.

Aj keď sa dokumentácia API na báze Javadoc stala veľmi užitočnou, my vývojári sa často tak veľmi ponáhľame a často sa cítime takí istí svojimi vlastnými schopnosťami, že je takmer nevyhnutné, že sa niekedy budeme snažiť robiť veci bez toho, aby sme si najskôr prečítali príručku. Z dôvodu tejto tendencie sa občas môžeme popáliť zneužitím konkrétneho API, a to aj napriek dokumentácii, ktorá nás varuje, aby sme ho takýmto spôsobom (nesprávne) nepoužívali. Diskutoval som o tom vo svojom blogovom príspevku na stránke Boolean.getBoolean (String) a v tomto príspevku som zdôraznil podobný problém súvisiaci s používaním konštruktora BigDecimal, ktorý akceptuje dvojník.

Na prvý pohľad by sa mohlo zdať, že konštruktor BigDecimal, ktorý akceptuje Java double, by ho vo všetkých prípadoch držal s pôvodne určenou presnosťou. Správa Javadoc pre tohto konštruktéra však výslovne varuje: „Výsledky tohto konštruktora môžu byť trochu nepredvídateľné.“ Ďalej vysvetľuje, prečo (dvojník nedokáže udržať presnú presnosť a je to zrejmé pri odovzdaní konštruktoru BigDecimal) a navrhuje, aby sa namiesto toho použil alternatívny konštruktor akceptujúci reťazec ako parameter. Dokumentácia tiež navrhuje použiť BigDecimal.valueOf (double) ako preferovaný spôsob prevodu double alebo float na BigDecimal.

Nasledujúci zoznam kódov slúži na demonštráciu týchto princípov a niekoľkých súvisiacich nápadov.

DoubleToBigDecimal.java

import java.math.BigDecimal; importovať statický java.lang.System.out; / ** * Jednoduchý príklad problémov spojených s používaním konštruktora BigDecimal * prijatie dvojníka. * * //marxsoftware.blogspot.com/ * / public class DoubleToBigDecimal {private final static String NEW_LINE = System.getProperty ("line.separator"); public static void main (final String [] argumenty) {// // Ukážte BigDecimal z double // final double primitiveDouble = 0,1; final BigDecimal bdPrimDoubleCtor = nový BigDecimal (primitiveDouble); final BigDecimal bdPrimDoubleValOf = BigDecimal.valueOf (primitiveDouble); final Double referenceDouble = Double.valueOf (0.1); final BigDecimal bdRefDoubleCtor = nový BigDecimal (referenceDouble); final BigDecimal bdRefDoubleValOf = BigDecimal.valueOf (referenceDouble); out.println ("Primitive Double:" + primitiveDouble); out.println ("Referencia Double:" + referenceDouble); out.println ("Primitive BigDecimal / Double via Double Ctor:" + bdPrimDoubleCtor); out.println ("Referencia BigDecimal / Double cez Double Ctor:" + bdRefDoubleCtor); out.println ("Primitívny BigDecimal / Double cez ValueOf:" + bdPrimDoubleValOf); out.println ("Referencia BigDecimal / Double cez ValueOf:" + bdRefDoubleValOf); out.println (NEW_LINE); // // Demonštrovať BigDecimal z floatu // final float primitiveFloat = 0,1f; final BigDecimal bdPrimFloatCtor = nový BigDecimal (primitiveFloat); final BigDecimal bdPrimFloatValOf = BigDecimal.valueOf (primitiveFloat); final Float referenceFloat = Float.valueOf (0,1f); final BigDecimal bdRefFloatCtor = nový BigDecimal (referenceFloat); final BigDecimal bdRefFloatValOf = BigDecimal.valueOf (referenceFloat); out.println ("Primitive Float:" + primitiveFloat); out.println ("Referenčná float:" + referenceFloat); out.println ("Primitive BigDecimal / Float via Double Ctor:" + bdPrimFloatCtor); out.println ("Referencia BigDecimal / Float cez Double Ctor:" + bdRefFloatCtor); out.println ("Primitívny BigDecimal / Float cez ValueOf:" + bdPrimFloatValOf); out.println ("Referencia BigDecimal / Float cez ValueOf:" + bdRefFloatValOf); out.println (NEW_LINE); // // Viac dôkazov o problémoch prenášania z float na double. // final double primitiveDoubleFromFloat = 0,1f; final Double referenceDoubleFromFloat = new Double (0.1f); final double primitiveDoubleFromFloatDoubleValue = nový Float (0.1f) .doubleValue (); out.println ("Primitive Double from Float:" + primitiveDoubleFromFloat); out.println ("Referenčný dvojitý z Float:" + referenceDoubleFromFloat); out.println ("Primitive Double z FloatDoubleValue:" + primitiveDoubleFromFloatDoubleValue); // // Použitie reťazca na udržanie presnosti z floatu na BigDecimal // final String floatString = String.valueOf (nový Float (0,1f)); final BigDecimal bdFromFloatViaString = nový BigDecimal (floatString); out.println ("BigDecimal z Float cez String.valueOf ():" + bdFromFloatViaString); }} 

Výstup zo spustenia vyššie uvedeného kódu sa zobrazuje na nasledujúcej snímke obrazovky.

Ako naznačuje výstup vyššie, problém dvojitého vrhania plaváka zabraňuje tomu, aby si človek udržal požadovanú presnosť pri prechode plaváka priamo na BigDecimal.valueOf (double) metóda. Na splnenie tohto príkladu je možné použiť reťazec ako prostriedok, ktorý je demonštrovaný podobným spôsobom pri prevode floatu na zdvojnásobenie nie tak bežným spôsobom.

Všimnite si, že Groovyho implicitné použitie BigDecimal pri použití Groovy a dynamického písania trochu mení hru. Toho sa možno dotknem v budúcom blogovom príspevku. Viac podrobností o otázkach s pohyblivou rádovou čiarkou (a zdôrazňujem „podrobnosti“) nájdete v časti Čo by mal každý počítačový vedec vedieť o aritmetike s pohyblivou rádovou čiarkou.

Tento príbeh, „Pozor: Zdvojnásobenie na BigDecimal v Jave“, bol pôvodne publikovaný spoločnosťou JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found