Currency

From Rosetta Code
Revision as of 23:15, 2 January 2014 by Sonia (talk | contribs) (New draft task and Go solution.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Currency is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Show how you might represent currency in a simple example. For this example, data will be two items with prices in dollars and cents, a quantity for each, and a tax rate. Use the values 4 hamburgers at $5.50 each, 2 milkshakes at $2.96 each, and a tax rate of 7.65%. Your program can hard code these values, but the representation must be exact. (Note for example that the IEEE 754 binary floating point representations of 2.96 and .0765 are not exact.)

Compute and output the total price before tax, the tax, and the total with tax, and show results on this page. The tax value must be computed by rounding to the nearest whole cent and this exact value (2.14, not 2.13588) must be added to the total price before tax. The output must show dollars and cents with a decimal point. The three results displayed should be 27.92, 2.14, and 30.06.

Go

<lang go>package main

import (

   "fmt"
   "log"
   "math/big"

)

// DC for dollars and cents. Value is an integer number of cents. type DC int64

func (dc DC) String() string {

   d := dc / 100
   if dc < 0 {
       dc = -dc
   }
   return fmt.Sprintf("%d.%02d", d, dc%100)

}

// Extend returns extended price of a unit price. func (dc DC) Extend(n int) DC {

   return dc * DC(n)

}

var one = big.NewInt(1) var hundred = big.NewRat(100, 1)

// ParseDC parses dollars and cents as a string into a DC. func ParseDC(s string) (DC, bool) {

   r, ok := new(big.Rat).SetString(s)
   if !ok {
       return 0, false
   }
   r.Mul(r, hundred)
   if r.Denom().Cmp(one) != 0 {
       return 0, false
   }
   return DC(r.Num().Int64()), true

}

// TR for tax rate. Value is an an exact rational. type TR struct {

   *big.Rat

}

func NewTR() TR {

   return TR{new(big.Rat)}

}

// SetString overrides Rat.SetString to return the TR type. func (tr TR) SetString(s string) (TR, bool) {

   if _, ok := tr.Rat.SetString(s); !ok {
       return TR{}, false
   }
   return tr, true

}

var half = big.NewRat(1, 2)

// Tax computes a tax amount, rounding to the nearest cent. func (tr TR) Tax(dc DC) DC {

   r := big.NewRat(int64(dc), 1)
   r.Add(r.Mul(r, tr.Rat), half)
   return DC(new(big.Int).Div(r.Num(), r.Denom()).Int64())

}

func main() {

   hamburgerPrice, ok := ParseDC("5.50")
   if !ok {
       log.Fatal("Invalid hamburger price")
   }
   milkshakePrice, ok := ParseDC("2.96")
   if !ok {
       log.Fatal("Invalid milkshake price")
   }
   taxRate, ok := NewTR().SetString("0.0765")
   if !ok {
       log.Fatal("Invalid tax rate")
   }
   totalBeforeTax := hamburgerPrice.Extend(4) + milkshakePrice.Extend(2)
   tax := taxRate.Tax(totalBeforeTax)
   total := totalBeforeTax + tax
   fmt.Printf("Total before tax: %8s\n", totalBeforeTax)
   fmt.Printf("             Tax: %8s\n", tax)
   fmt.Printf("           Total: %8s\n", total)

}</lang>

Output:
Total before tax:    27.92
             Tax:     2.14
           Total:    30.06