Currency: Difference between revisions

Content added Content deleted
m (added a name for the number (in the task's preamble).)
Line 963: Line 963:
23683000000000006.16
23683000000000006.16
</pre>
</pre>

=={{header|Nim}}==
{{libheader|bignum}}

Nim doesn’t provide a standard module to deal with decimal values. There exist some third party modules but we have chosen to use the “bignum” library which provides big integers and big rationals.

<lang Nim>import strutils
import bignum

type Currency = Int

#---------------------------------------------------------------------------------------------------

func currency(units, subunits: int): Currency =
## Build a currency from units and subunits.
## Units may be negative. Subunits must be in range 0..99.
if subunits notin 0..99:
raise newException(ValueError, "wrong value for subunits")
result = if units >= 0: newInt(units * 100 + subunits)
else: newInt(subunits * 100 - subunits)

#---------------------------------------------------------------------------------------------------

func currency(value: string): Currency =
## Build a currency from a string.
## Negative values are allowed. At most two digits are allowed for subunits.

const StartingChars = Digits + {'-'}
if value.len == 0 or value[0] notin StartingChars:
raise newException(ValueError, "wrong currency string")

# process sign and units.
var units = newInt(0)
var subunits = 0
let sign = if value[0] == '-': -1 else: 1
var idx = if sign == 1: 0 else: 1
while idx < value.len:
if value[idx] notin Digits: break
units = 10 * units + ord(value[idx]) - ord('0')
inc idx

# Process separator.
if idx <= value.high:
if value[idx] != '.':
raise newException(ValueError, "expected a separator")
inc idx

# Process subunits.
for _ in 0..1:
let c = if idx >= value.len: '0' else: value[idx]
if c notin Digits:
raise newException(ValueError, "wrong value for subunits")
subunits = 10 * subunits + ord(c) - ord('0')
inc idx

if idx <= value.high:
raise newException(ValueError, "extra characters after subunits digits")

result = sign * (units * 100 + subunits)

#---------------------------------------------------------------------------------------------------

func `//`(a, b: int): Rat =
## Create a rational value.
newRat(a, b)

#---------------------------------------------------------------------------------------------------

func percentage(a: Currency; p: Rat): Currency =
## Compute a percentage on currency value "a".
## Returned value is rounded to nearest integer.

(a * p.num * 10 div p.denom + 5) div 10

#---------------------------------------------------------------------------------------------------

func `$`(a: Currency): string =
## Build a string representation of a currency value.

result = bignum.`$`(a div 100) & '.' & ($(a mod 100).toInt).align(2, '0')

#———————————————————————————————————————————————————————————————————————————————————————————————————

let hamburgers = currency(5, 50) * int 4_000_000_000_000_000
let milkshakes = currency("2.86") * 2
let rate = 765 // 10_000
let beforeTax = hamburgers + milkshakes
let tax = beforeTax.percentage(rate)
let total = beforeTax + tax

# Find the maximum length of numerical value representations.
let beforeTaxStr = $beforeTax
let taxStr = $tax
let totalStr = $total
let length = max([beforeTaxStr.len, taxStr.len, totalStr.len])

# Display the results.
echo "Total price before tax: ", beforeTaxStr.align(length)
echo "Tax: ", taxStr.align(length)
echo "Total with tax: ", totalStr.align(length)</lang>

{{out}}
<pre>Total price before tax: 22000000000000005.72
Tax: 1683000000000000.44
Total with tax: 23683000000000006.16</pre>


=={{header|OCaml}}==
=={{header|OCaml}}==