Now, if you build a small scale web page, you may never encounter rounding errors when dealing with this data type. However, if you are in the business of handling big amounts of cash, where fractions of a cent spread over millions of transactions could render losses in the tens or hundreds of thousands of dollars, you definitely should rethink your strategy.
Right now, what most people do, is using either BigDecimal or even calculating everything with 64 bit integers to avoid dealing with floating point arithmetic inaccuracies found in the primitive double data type.
There is nothing wrong in doing this, however, what about actually treating those essentially ambiguous floating point numbers as amounts of money. What about a data type called Money so you give those numbers a meaning. What if there was built in support in Java that treats money as a unit of measurement so you give those numbers a clear meaning?
A framework for this will likely find it's way into Java 7 and for those of you wanting to get a head-start is to download a fully functioning and mature reference implementation called JScience. I used it in one of my recent projects and I would like to share some very simple examples.
Converting from Euros to Swedish Crownes
import org.jscience.economics.money.Currency;
import org.jscience.physics.amount.Money;
import javax.measure.unit.Unit
public class ConvertCurrency {
public static void convertSekToEur(double value) {
Currency sek = new Currency("SEK");
// Exchange rate SEK to SEK is 1.00
sek.setExchangeRate(1.00);
Currency eur = new Currency("EUR");
// Exchange rate for EUR to SEK is 9.72
eur.setExchangeRate(9.72);
// Amount of money in SEK received
Amount<Money> received = Amount.valueOf(value, sek);
// Units should be printed with the Euro symbol
UnitFormat.getInstance().label(Currency.EUR, "€");
// Convert to SEK to EUR and get a localized text string
String res = received.to(eur).toText();
// Should print "value €", depending on Locale
System.out.println("Teller returned: " + res);
}
}I know, this isn't all that impressive, but if you investigate the API further, you will notice, that very powerful things can be done with JScience.
Also, be aware that in the above example, I didn't set a reference currency. This means, that I had to set the exchange rate for both currencies. If I'd set SEK as the reference currency by using the Currency.setReferenceCurrency-method, the exchange rate for SEK would have been obsolete. Naturally, most apps will have a reference currency.
The distance in money
Imagine you were to put 50 Euro bank notes on the street all the way from Stockholm to Malmö. That's a distance of about 700 kilometers. How much money would you actually need?
import org.jscience.economics.money.Currency;
import org.jscience.economics.money.Money;
import org.jscience.physics.amount.Amount;
import javax.measure.quantity.Length;
import javax.measure.unit.SI;
public class DistanceInMoney {
public static void main(String[] args) {
// Distance between Stockholm and Malmö
Amount<Length> distanceSthlmMmo = Amount.valueOf(700, SI.KILOMETER);
// Length of a banknote
Amount<Length> lengthBankNote = Amount.valueOf(15, SI.CENTIMETER);
// Value of that banknote
Amount<Money> bankNoteValue = Amount.valueOf(50, Currency.EUR);
// Calculate how many banknotes are needed
Amount<?> bankNotesNeeded = distanceSthlmMmo.to(SI.CENTIMETER).divide(lengthBankNote);
// Show how much money you will need in total
System.out.println("Money needed: " + bankNoteValue.times(bankNotesNeeded));
}
}Of course, this can also be done manually, but it's just to show that you give a meaning to numbers by using Amount<Length> or Amount<Money>. As in this number is an amount of money.
Calculating the cost for a trip
The last example is quite neat also. I admit, it's a simplified version of an example provided by the makers of JScience, however, I am not ashamed. I like it and that's why I post it :-)
So, how much does it cost to drive from Stockholm to Uppsala with my car...
import org.jscience.economics.money.Currency;
import org.jscience.economics.money.Money;
import org.jscience.physics.amount.Amount;
import javax.measure.quantity.Length;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
public class TripCost {
public static void main(String[] args) {
// Our reference currency is SEK
Currency.setReferenceCurrency(new Currency("SEK"));
// My car drives 12,5km with one liter of petrol
Amount<?> enginesThirst = Amount.valueOf(12.5, SI.KILOMETER.divide(NonSI.LITER));
// Fuel costs 12 SEK per liter
Amount<?> fuelPrice = Amount.valueOf(12, Currency.getReferenceCurrency().divide(NonSI.LITER));
// The distance to Uppsala is 50km
Amount<Length> distanceToUppsala = Amount.valueOf(50, SI.KILOMETER);
// Calculate the cost
Amount<Money> cost = distanceToUppsala.divide(enginesThirst).times(fuelPrice).to(Currency.getReferenceCurrency());
System.out.println("Trip costs: " + cost.toString());
}
}Again, this is no magic. You can do all this manually, however, isn't it quite helpful to actually treat units and amounts specifically as units, amounts and quantities?
Conclusion
So, what are the benefits besides the obvious? Well, JScience has a wealth of SI and NonSI units to do calculations, it has special numerical datatypes which guarantee IEEE754 accuracy and especially for scientific applications, this is a great treat to us all.
You probably remember the disaster with a NASA space probe a couple of years ago. Due to some mix-ups with units of measurement, millions went up in smoke. This sort of ambiguity should be a thing of the past with JScience (JSR-275).
0 comments:
Post a Comment