CSC/ECE 517 Fall 2012/ch6 1w49 aa

From Expertiza_Wiki
Revision as of 00:26, 4 October 2012 by Aabhole (talk | contribs)
Jump to navigation Jump to search

Representing money

Introduction

In most commercial applications we are required to create, manipulate and store currency values. The most important concerns about the representation and storage of money are accuracy and consistency. While manipulating currency values the precision to which calculations are done will affect the accuracy. Also while storing and retrieving the currency values, the correct storage types will ensure consistency. These concerns become even more significant in scenarios where we have multiple currencies and conversion operations between them. This page first discusses the merits of an approach described by Skrien and also critically analyses a number of other approaches and their relative advantages and disadvantages. This page first discusses the design approach described by Skrien. Most of the real program implementations are also inspired from the same approach. We discuss some of them, their advantages and disadvantages in the following sections.


Representation using Premitive Data Types

Floating point Representation

Money can be represented using floating point numbers. At a first look, this seems the most logical approach to handle money in programs. While floating-point data types are capable of representing extremely large positive and negative numbers and offer the equivalent of many decimal digits of precision, they are nonetheless inexact when it comes to representing decimal numbers. For example, 9.47 is stored as 9.479999542236328125. Thus performing arithmetic operations on such numbers further adds inaccuracy to the result.

Integer Representation

A single Integer can be used to represent money value. Such an approach requires an assumption of an implicit decimal point. For example $24.68 can be represented as 2468 considering the fact that for US Dollar representation, the decimal point is before the last two digits. This approach has the advantage of requiring less storage and accuracy in calculations. Drawbacks however crawl in when dealing with money belonging to different currencies having different implicit decimal points.

Class Representation

In Object Oriented programming languages, a class representation can be used for money. Such a class provides encapsulation and the users need not concern themselves as to how the positive and negative money is represented. Using objects to represent money can also help in determining logical errors like adding denominations in different currencies. Such errors might slip through if we use primitive representation of money.

Ruby - Money Gem

A gem named Money provides an implementation similar in some aspects as one specified by Skrien. It represents monetary values as integers in cents. Floating point rounding errors resulting from operations on decimals can be avoided using this implementation. The Money class uses Bank and Currency classes internally to define the attributes and behavior of a money object. It has built in ability to parse a money and currency string into corresponding Money/Currency object. The object of the type Money is immutable and conversions and operations result in creation of a new object except that the currency identifier can be changed after the creation of the money object. Mentioned below is an example of the usage of the money class

require 'money'

  1. 10.00 USD

money = Money.new(1000, "USD") money.cents #=> 1000 money.currency #=> Currency.new("USD")

  1. Comparisons

Money.new(1000, "USD") == Money.new(1000, "USD") #=> true Money.new(1000, "USD") == Money.new(100, "USD") #=> false Money.new(1000, "USD") == Money.new(1000, "EUR") #=> false Money.new(1000, "USD") != Money.new(1000, "EUR") #=> true

  1. Arithmetic

Money.new(1000, "USD") + Money.new(500, "USD") == Money.new(1500, "USD") Money.new(1000, "USD") - Money.new(200, "USD") == Money.new(800, "USD") Money.new(1000, "USD") / 5 == Money.new(200, "USD") Money.new(1000, "USD") * 5 == Money.new(5000, "USD")

  1. Currency conversions

some_code_to_setup_exchange_rates Money.new(1000, "USD").exchange_to("EUR") == Money.new(some_value, "EUR")

Each money object is associated with a bank object which is responsible for the currency exchange. The Bank class is also an internal class to the Money class but it resides at the class level. This means that the Bank object follows the Singleton pattern in that only one Bank object exists across all of the currency. The purpose of the Bank is to maintain information related to currency values such that currency conversion can take place.This object uses a class name VariableExchange which performs the exchange. By default the class has no knowledge of exchange rates as they change dynamically. The gem provides APIs for exchanging money from one currency to other. This can either be done by manually supplying exchange rates or by using exchange rates available at major banks and currency exchange websites.Since the Bank class inherits from an interface, this allows for extensible money conversion schemes such as being able to 'scrape' data from the internet and use it to populate conversion ratios.

bank = Money::Bank::VariableExchange.new bank.add_rate("USD", "CAD", 1.24515) bank.add_rate("CAD", "USD", 0.803115)

c1 = 100_00.to_money("USD") c2 = 100_00.to_money("CAD")

  1. Exchange 100 USD to CAD:

bank.exchange_with(c1, "CAD") #=> #<Money @cents=1245150>

  1. Exchange 100 CAD to USD:

bank.exchange_with(c2, "USD") #=> #<Money @cents=803115>

An attribute of the type Currency stores the currency the money is in. The currency class by default has a table which is constant and has a list of known currencies. It specifies the three letter ISO4217 code for currency along with the monetary unit, their symbols and delimiters. The class also implements a CurrencyLoader class through which currency information can be loaded from specified locations. This allows the list to be easily manageable. Below is an example of the USD currency information loaded by a default JSON configuration file.

"usd": { "priority": 1, "iso_code": "USD", "name": "United States Dollar", "symbol": "$", "subunit": "Cent", "subunit_to_unit": 100, "symbol_first": true, "html_entity": "$", "decimal_mark": ".", "thousands_separator": ",", "iso_numeric": "840"

 },

The gem provides APIs for exchanging money from one currency to other. This can either be done by manually supplying exchange rates or by using exchange rates available at major banks and currency exchange websites. The implementation differs from Skrien's approach in one major aspect that is it does not have It is also worthwhile to mention a plugin named acts_as_money which makes it easier to work with money object. Inclusion of this gem allows the programmer to assume there are 2 columns in the database namely cents and currency. Mentioned below is an example of the implementation.

 acts_as_money
 money :rate, :cents => :rate_in_cents, :currency => :rate_currency
 money :discount, :cents => :discount_in_cents, :currency => false

end

acts_as_money allows you to pass a String, Fixnum, Float or Money object as a parameter to the setter, and it will call #to_money to convert it to a Money object. This makes it convenient for using money fields in forms.

r = Room.new :rate => "100.00" r.rate # returns <Money:0x249ef9c @currency="USD", @cents=10000>

Advantages


The internal CurrencyLoader class allows for easily extensible currency information sources, even allowing currency information to be dynamically loaded Due to the Bank implementation, additional class implementations can be loaded and changed out at runtime to allow for more complex, an potentially real-time, currency conversion information The fact that the Currency and Bank classes are internal to theMoney class, the user doesn't have to know about their implementation Ruby's dynamic nature allows for classes to be internal to Money, yet defined in separate files from the Money class, helping to keep the code modular from a developers point of view The addition of to_money() methods to basic Ruby primitives makes it easier to create money from just about any type Since Ruby supports arbitrarily large integer values, there is theoretically no upper bound to the amount of money that can be stored in a Money object

Disadvantages


Doesn't support multiple currency types in a single object A Money object is immutable except in one way, ability to change currency type, which is an inconsistency that could easily have been avoided While the addition of to_money() methods to primitive types makes some things easier, it adds the additional ability to incorrectly combine an object of type Money with one that is not Since the Bank object is a singleton contained within the Moneyclass, any modifications to currency exchange rates require locking of the Bank object which could result in performance degradation if exchange rates are modified often