/*
-----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)
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-----
*/