/* -----BEGIN PGP SIGNED MESSAGE----- */ import java.math.BigDecimal; //import com.ibm.math.BigDecimal; // use IBM's BigDecimal class if you can import java.util.Locale; import java.io.*; // for I/O streams in test routine main() only /** This class is just a trivial demo of how to do conversions between strings and numbers in a fully WORA (Write Once Run Anywhere) way. Java's BigDecimal class and my own BDFormat class are used (instead of Java's Double, Long and NumberFormat classes) for two main reasons.

1. Double and Long store numbers as binaries, creating subtle pitfalls and limits with which a programmer using those classes must become familiar if unintended results are to be avoided. While Double and Long perform better (they take advantage of the CPU's floating point routines), speed in financial and arithmetic operations is rarely as important as accuracy.

2. NumberFormat has two major limitations in its current form: its format() routine does not handle BigDecimal objects correctly, and its parse() routine does not treat spaces correctly in locales that use the space as a grouping separator. My BDFormat class makes extensive use of NumberFormat's format() and parse() methods but adds the functionality to fix both these problems. Also, an attempt to format() a number too large for NumberFormat will now throw an exception instead of just quietly returning incorrect output.

Finally, a greatly imporved BigDecimal class is now available as com.ibm.math.BigDecimal. It's up to 23-times faster and it does decimal arithmetic in a way humans (other than numerics specialists) would expect. Get it from IBM alphaWorks.

To use this class (while you get used to Java's "new math" as I see it), just instantiate (assign a variable to) NumberConverter and call one of the methods, as in:
       BigDecimal big = new BigDecimal( someNumber );
       String str = new NumberConverter().writeDecimal( big );
    or
       Locale loc_fr = new Locale( "fr", "FR" );
       String input = "-12 345,678 Fr";
       BigDecimal bd_in = new NumberConverter(loc).readInteger( input );
       // bd_in now contains a BigDecimal whose value is -12346 (after rounding)

To use the BDFormat class directly (once you are comfortable with this "new math"), instantiate BDFormat and call one of the methods. For example, to display an amount in several currencies, with decimals aligned in a 30-column field, you can write:
       BigDecimal dollarAmount = new BigDecimal( amountAsDoubleOrString );
       BigDecimal francsPerDollar = new BigDecimal(5.6755);
       BigDecimal liraPerDollar = new BigDecimal(1676.00);
       BigDecimal kronerPerDollar = new BigDecimal(6.4310);
       // if using System.out, and en_US is the default locale, you can write:
       System.out.println(
         "Soccer tickets........." + new BDFormat().curformat( dollarAmount, 30) + "\n"
        +"Billets du football...." + new BDFormat( new Locale("fr","FR") ).curformat(
                                         dollarAmount.multiply(francsPerDollar), 30) + "\n"
        +"Biglietti di soccer...." + new BDFormat( new Locale("it","IT") ).curformat(
                                         dollarAmount.multiply(liraPerDollar), 30) + "\n"
        +"Fodboldbilletter......." + new BDFormat( new Locale("da","DK") ).curformat(
                                         dollarAmount.multiply(kronerPerDollar), 30)  );
    which gives the output:
      Soccer tickets.......................... $195.28
      Billets du football.................... 1 108,31 F
      Biglietti di soccer............... L. 327.289
      Fodboldbilletter.................... kr 1.255,85
@author Tooy Dahlman @version 1.0 - November 1998 */ public class NumberConverter { /** The BigDecimal number formatter. */ private BDFormat nf; /** The usual rounding mode for financial apps, known as "HALF_EVEN". */ private int roundingMode = BigDecimal.ROUND_HALF_EVEN; /** Default constructor, uses the default locale. */ public NumberConverter() { this( Locale.getDefault() ); } /** Locale-specific constructor. */ public NumberConverter( Locale loc ) { nf = new BDFormat( loc ); } /** Get a BigDecimal (less any decimal fraction) from the string you supply. */ public BigDecimal readInteger( String input ) { BigDecimal temp = nf.parse(input); return temp.setScale(0,roundingMode); } /** Get a BigDecimal from the string you supply. */ public BigDecimal readDecimal( String input) { return nf.parse(input); } /** Get a formatted string from the BigDecimal amount you supply. */ public String writeInteger ( BigDecimal amount ) { amount = amount.setScale(0,roundingMode); return nf.format( amount ) ; } /** Get a formatted string from the BigDecimal amount you supply. */ public String writeDecimal( BigDecimal amount) { return nf.format( amount ) ; } /** Test routine: try out the parsing and formatting methods. */ public static void main(String[] args) throws IOException { Locale loc; if (args.length < 2) { loc = Locale.getDefault(); } else { loc = new Locale( args[0], args[1] ); } /* endif */ NumberConverter nc = new NumberConverter( loc ); BigDecimal bd; BigDecimal MULTIPLIER = new BigDecimal(1024); String input = null, output = null; BufferedReader ins = new BufferedReader( new InputStreamReader( System.in ) ); PrintWriter outs = new PrintWriter( new BufferedWriter( new OutputStreamWriter( System.out ) ), true); while (true) { outs.print("\nEnter an integer: "); outs.flush(); // read in some input as text, and exit if no text. input = ins.readLine().trim(); // *************************************************************** // Using "TextField tf_in" as the input source, replace the above // line with: // input = tf_in.getText(); // *************************************************************** if( input.length() < 1 ) { outs.println("Nov 1998 - adahlman@jps.net"); ins.close(); outs.close(); System.exit(0); } // get a useable number from the input string, then do a multiply. bd = nc.readInteger( input ); bd = bd.multiply( MULTIPLIER ); // write out the result as a string outs.println("Your input times " + MULTIPLIER + "==> " + nc.writeInteger(bd) ); // *************************************************************** // Using "TextField tf_out as the output destination, replace the // above line with: // tf_out.setText( nc.writeInteger(bd) ); // *************************************************************** // Now prove this worked by dividing to get the original number back. bd = bd.divide(MULTIPLIER, 0, nc.roundingMode); outs.println("Dividing that by " + MULTIPLIER + "==> " + nc.writeInteger( bd ) ); } /* endwhile */ } } /* Sample output: [F:\Java11\adahlman\test]java NumberConverter da DK Enter an integer: 12.345.678,901 Your input times 1024==> 12.641.975.296 Dividing that by 1024==> 12.345.679 Enter an integer: -9.876,49 Your input times 1024==> -10.113.024 Dividing that by 1024==> -9.876 Enter an integer: kr -9.876 Your input times 1024==> -10.113.024 Dividing that by 1024==> -9.876 -----BEGIN PGP SIGNATURE----- Version: 2.6.2 iQCVAwUBNl35PWbsFmrW0oYFAQEmMgQAmWpPN16OKEYc88JTh2d4v9fpzZZPffjF PKadxsCqYrEbRJvDsrDN//3o1IcDsfGEWzYwVtuqr+jsvNAHniSDQG3NNcmCalF8 LUuknSIdFhos0upogupJMyRIcuYJlBBFlbNmSdNMFPtn+L1lTBx1ygWIbGzopOJC GoyHoFnaHl0= =YP8d -----END PGP SIGNATURE----- */