⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{task}}
;Task: Show how to represent currency in a simple example, using a data type that represent exact values of dollars and cents.
;Note: The '''IEEE 754''' binary floating point representations of numbers like '''2.86''' and '''.0765''' are not exact.
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: ::* 4000000000000000 hamburgers at $5.50 each ::* 2 milkshakes at $2.86 each, and ::* a tax rate of 7.65%.
(That number of hamburgers is a 4 with 15 zeros after it. The number is contrived to exclude naïve task solutions using 64 bit floating point types.)
Compute and output (show results on this page): ::* the total price before tax ::* the tax ::* the total with tax
The tax value must be computed by rounding to the nearest whole cent and this exact value 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: ::* 22000000000000005.72 ::* 1683000000000000.44 ::* 23683000000000006.16
Dollar signs and thousands separators are optional.
ALGOL 68
{{works with|ALGOL 68G|Any - tested with release 2.8.3.win32}}
BEGIN
# currency calculations #
# simple fixed point type, LONG INT is 64-bit in Algol 68G #
MODE FIXED = STRUCT( LONG INT value
, INT decimals
, INT fraction modulus
);
# make CURRENCY a synonym for FIXED #
MODE CURRENCY = FIXED;
# dyadic operator so we can write e.g. 5 DOLLARS 50 to construct #
# a CURRENCY value with 2 decimal places #
PRIO DOLLARS = 9;
OP DOLLARS = ( LONG INT v, INT dp )CURRENCY: ( ( v * 100 ) + dp, 2, 100 );
OP DOLLARS = ( INT v, INT dp )CURRENCY: LENG v DOLLARS dp;
# issues an error message and stops the program if a has a different #
# number of decimal places to b #
PROC check compatible = ( CURRENCY a, b )VOID:
IF decimals OF a /= decimals OF b THEN print( ( "Incompatible CURRENCY values", newline ) ); stop FI;
# operators to multiply CURRENCY values by integers #
OP * = ( CURRENCY v, LONG INT m )CURRENCY: ( value OF v * m, decimals OF v, fraction modulus OF v );
OP * = ( CURRENCY v, INT m )CURRENCY: v * LENG m;
# returns the CURRENCY value a + b #
OP + = ( CURRENCY a, CURRENCY b )CURRENCY:
BEGIN
check compatible( a, b );
( value OF a + value OF b, decimals OF a, fraction modulus OF a )
END # + # ;
# multiplies the CURRENCY value a by the FIXED value b, #
# rounding the result to the decimal places of a #
OP * = ( CURRENCY a, FIXED b )CURRENCY:
BEGIN
LONG INT result := ( value OF a * value OF b );
IF decimals OF b > 0 THEN
INT d = fraction modulus OF b;
LONG INT abs result := ABS result;
INT extra places = SHORTEN ( abs result MOD d );
abs result OVERAB d;
IF extra places >= d OVER 2 THEN abs result +:= 1 FI;
IF result < 0 THEN result := - abs result ELSE result := abs result FI
FI;
( result, decimals OF a, fraction modulus OF a )
END # * # ;
# converts a FIXED value to a STRING with the appropriate number of #
# decimal places #
OP TOSTRING = ( FIXED v )STRING:
IF decimals OF v < 1 THEN
whole( value OF v, 0 )
ELSE
INT d = fraction modulus OF v;
STRING result := whole( value OF v OVER d, 0 );
STRING dp := whole( ( ABS value OF v ) MOD d, - decimals OF v );
FOR i FROM LWB dp TO UPB dp DO IF dp[ i ] = " " THEN dp[ i ] := "0" FI OD;
result + "." + dp
FI # TOSTRING # ;
# Task calculations #
CURRENCY hb = 5 DOLLARS 50 * LONG 4000000000000000;
CURRENCY ms = 2 DOLLARS 86 * 2;
FIXED rate = ( 765, 4, 10 000 ); # 0.0765 #
CURRENCY net = hb + ms;
CURRENCY tax = net * rate;
CURRENCY total = net + tax;
print( ( "before tax: ", TOSTRING net, newline ) );
print( ( "tax: ", TOSTRING tax, newline ) );
print( ( "total: ", TOSTRING total, newline ) )
END
{{out}}
before tax: 22000000000000005.72
tax: 1683000000000000.44
total: 23683000000000006.16
AWK
version 1
# syntax: GAWK -M -f CURRENCY.AWK
# using GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2, GNU MP 5.1.2)
BEGIN {
PREC = 100
hamburger_p = 5.50
hamburger_q = 4000000000000000
hamburger_v = hamburger_p * hamburger_q
milkshake_p = 2.86
milkshake_q = 2
milkshake_v = milkshake_p * milkshake_q
subtotal = hamburger_v + milkshake_v
tax = subtotal * .0765
printf("%-9s %8s %18s %22s\n","item","price","quantity","value")
printf("hamburger %8.2f %18d %22.2f\n",hamburger_p,hamburger_q,hamburger_v)
printf("milkshake %8.2f %18d %22.2f\n\n",milkshake_p,milkshake_q,milkshake_v)
printf("%37s %22.2f\n","subtotal",subtotal)
printf("%37s %22.2f\n","tax",tax)
printf("%37s %22.2f\n","total",subtotal+tax)
exit(0)
}
Output:
item price quantity value
hamburger 5.50 4000000000000000 22000000000000000.00
milkshake 2.86 2 5.72
subtotal 22000000000000005.72
tax 1683000000000000.41
total 23683000000000006.13
version 2
# syntax: GAWK -M -f CURRENCY2.AWK
# using GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2, GNU MP 5.1.2)
# INT is used to define values and do math; results then converted to FLOAT
BEGIN {
PREC = 100
hamburger_p = 550
hamburger_q = 4000000000000000
hamburger_v = hamburger_p * hamburger_q
milkshake_p = 286
milkshake_q = 2
milkshake_v = milkshake_p * milkshake_q
subtotal = hamburger_v + milkshake_v
tax = subtotal * 765
subtotal /= 100
tax /= 1000000
printf("%-9s %8s %18s %22s\n","item","price","quantity","value")
printf("hamburger %8.2f %18d %22.2f\n",hamburger_p/100,hamburger_q,hamburger_v/100)
printf("milkshake %8.2f %18d %22.2f\n\n",milkshake_p/100,milkshake_q,milkshake_v/100)
printf("%37s %22.2f\n","subtotal",subtotal)
printf("%37s %22.2f\n","tax",tax)
printf("%37s %22.2f\n","total",subtotal+tax)
exit(0)
}
Output:
item price quantity value
hamburger 5.50 4000000000000000 22000000000000000.00
milkshake 2.86 2 5.72
subtotal 22000000000000005.72
tax 1683000000000000.44
total 23683000000000006.16
C
This implementation uses the GMP library for arbitrary precision arithmetic. The only data type used here is '''mpf_t''', the following text is from the GMP documentation :
Floating point number or Float for short, is an arbitrary precision mantissa with a limited precision exponent. The C data type for such objects is mpf_t. For example:
mpf_t fp;
One remark about the code, notice that for setting all other variables the '''mpf_set_d''' function is used:
mpf_set_d(burgerUnitPrice,5.50);
mpf_set_d(milkshakePrice,2 * 2.86);
mpf_set_d(burgerNum,4000000000000000);
mpf_set_d(milkshakeNum,2);
But when it comes to the tax rate, it's '''mpf_set_str''':
mpf_set_str(tax,"0.0765",10);
The reason is a weird rounding off error which happens if the mpf_set_d function is used. Documentation and example usages of GMP are very rare on the net possibly because it is used almost exclusively by academia and high tech industries. The implementation below is the result of a lot of fiddling, gotchas and lessons learnt, just how good programming should always be :) {{libheader|GMP}}
#include<stdio.h>
#include<gmp.h>
int main()
{
mpf_t burgerUnitPrice, milkshakePrice, burgerTotalPrice, totalPrice, tax, burgerNum, milkshakeNum;
mpf_inits(burgerUnitPrice, milkshakePrice, burgerTotalPrice, totalPrice, tax,burgerNum, milkshakeNum,NULL);
mpf_set_d(burgerUnitPrice,5.50);
mpf_set_d(milkshakePrice,2 * 2.86);
mpf_set_d(burgerNum,4000000000000000);
mpf_set_d(milkshakeNum,2);
mpf_mul(burgerTotalPrice,burgerNum,burgerUnitPrice);
mpf_add(totalPrice,burgerTotalPrice,milkshakePrice);
mpf_set_str(tax,"0.0765",10);
mpf_mul(tax,totalPrice,tax);
gmp_printf("\nTotal price before tax : $ %.*Ff", 2, totalPrice);
gmp_printf("\nTotal tax : $ %.*Ff", 2, tax);
mpf_add(totalPrice,totalPrice,tax);
gmp_printf("\nTotal price after tax : $ %.*Ff", 2, totalPrice);
return 0;
}
Output:
Total price before tax : $ 22000000000000005.72
Total tax : $ 1683000000000000.44
Total price after tax : $ 23683000000000006.16
C#
The built in C# type decimal has a max value of 79228162514264337593543950335.
using System;
using System.Collections.Generic;
namespace Currency
{
class Program
{
static void Main(string[] args)
{
MenuItem hamburger = new MenuItem() { Name = "Hamburger", Price = 5.5M };
MenuItem milkshake = new MenuItem() { Name = "Milkshake", Price = 2.86M };
IList<CartItem> cart = new List<CartItem>();
cart.Add(new CartItem() { item = hamburger, quantity = 4000000000000000 });
cart.Add(new CartItem() { item = milkshake, quantity = 2 });
decimal total = CalculateTotal(cart);
Console.WriteLine(string.Format("Total before tax: {0:C}", total));
// Add Tax
decimal tax = total * 0.0765M;
Console.WriteLine(string.Format("Tax: {0:C}", tax));
total += tax;
Console.WriteLine(string.Format("Total with tax: {0:C}", total));
}
private static decimal CalculateTotal(IList<CartItem> cart)
{
decimal total = 0M;
foreach (CartItem item in cart)
{
total += item.quantity * item.item.Price;
}
return total;
}
private struct MenuItem
{
public string Name { get; set; }
public decimal Price { get; set; }
}
private struct CartItem
{
public MenuItem item { get; set; }
public decimal quantity { get; set; }
}
}
}
{{out}}
Total before tax: $22,000,000,000,000,005.72
Tax: $1,683,000,000,000,000.44
Total with tax: $23,683,000,000,000,006.16
Clojure
{{libheader|clojurewerkz/money}}
(require '[clojurewerkz.money.amounts :as ma])
(require '[clojurewerkz.money.currencies :as mc])
(require '[clojurewerkz.money.format :as mf])
(let [burgers (ma/multiply (ma/amount-of mc/USD 5.50) 4000000000000000)
milkshakes (ma/multiply (ma/amount-of mc/USD 2.86) 2)
pre-tax (ma/plus burgers milkshakes)
tax (ma/multiply pre-tax 0.0765 :up)]
(println "Total before tax: " (mf/format pre-tax))
(println " Tax: " (mf/format tax))
(println " Total with tax: " (mf/format (ma/plus pre-tax tax))))
{{out}}
Total before tax: $22,000,000,000,000,005.72
Tax: $1,683,000,000,000,000.44
Total with tax: $23,683,000,000,000,006.16
COBOL
COBOL supports up to 31 digits of decimal precision, so won't need any fancy currency/BigInteger types!
During calculations the default ROUNDED MODE IS clause, when specified, is NEAREST-AWAY-FROM-ZERO. When ROUNDED is not specified, the default mode is TRUNCATION. The term "banker's rounding" implies NEAREST-EVEN.
{{works with|GNU Cobol|2.1}}
SOURCE FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. currency-example.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Burger-Price CONSTANT 5.50.
01 Milkshake-Price CONSTANT 2.86.
01 num-burgers PIC 9(18) VALUE 4000000000000000.
01 num-milkshakes PIC 9(18) VALUE 2.
01 tax PIC 9(18)V99.
01 tax-edited PIC $(17)9.99.
01 Tax-Rate CONSTANT 7.65.
01 total PIC 9(18)V99.
01 total-edited PIC $(17)9.99.
PROCEDURE DIVISION.
COMPUTE total rounded, total-edited rounded =
num-burgers * Burger-Price + num-milkshakes * Milkshake-Price
DISPLAY "Total before tax: " total-edited
COMPUTE tax rounded, tax-edited rounded = total * (Tax-Rate / 100)
DISPLAY " Tax: " tax-edited
ADD tax TO total GIVING total-edited rounded
DISPLAY " Total with tax: " total-edited
.
END PROGRAM currency-example.
{{out}}
Total before tax: $22000000000000005.72
Tax: $1683000000000000.44
Total with tax: $23683000000000006.16
Factor
Factor's ratio type can handle arbitrary-precision calculations with rational numbers. The money vocabulary implements convenience words for treating rationals as money. The DECIMAL: parsing word is used to convert the tax rate 0.0765 to a ratio 153/2000. The money. word is used to print the subtotal 22000000000000005+18/25, tax 1683000000000000+21879/50000, and total 23683000000000006+7879/50000 formatted as you would expect.
USING: combinators.smart io kernel math math.functions money ;
10 15 ^ 4 * 5+50/100 * ! hamburger subtotal
2 2+86/100 * ! milkshake subtotal
+ ! subtotal
dup DECIMAL: 0.0765 * ! tax
[ + ] preserving ! total
"Total before tax: " write [ money. ] 2dip
"Tax: " write [ money. ] dip
"Total with tax: " write money.
{{out}}
Total price before tax: $22,000,000,000,000,005.72
Tax: $1,683,000,000,000,000.44
Total with tax: $23,683,000,000,000,006.16
F#
open System
let hamburgers = 4000000000000000M
let hamburgerPrice = 5.50M
let milkshakes = 2M
let milkshakePrice = 2.86M
let taxRate = 0.0765M
let total = hamburgers * hamburgerPrice + milkshakes * milkshakePrice
let tax = total * taxRate
let totalWithTax = total + tax
printfn "Total before tax:\t$%M" <| Math.Round (total, 2)
printfn " Tax:\t$%M" <| Math.Round (tax, 2)
printfn " Total:\t$%M" <| Math.Round (totalWithTax, 2)
{{out}}
Total before tax: $22000000000000005.72
Tax: $1683000000000000.44
Total with tax: $23683000000000006.16
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.86")
if !ok {
log.Fatal("Invalid milkshake price")
}
taxRate, ok := NewTR().SetString("0.0765")
if !ok {
log.Fatal("Invalid tax rate")
}
totalBeforeTax := hamburgerPrice.Extend(4000000000000000) +
milkshakePrice.Extend(2)
tax := taxRate.Tax(totalBeforeTax)
total := totalBeforeTax + tax
fmt.Printf("Total before tax: %22s\n", totalBeforeTax)
fmt.Printf(" Tax: %22s\n", tax)
fmt.Printf(" Total: %22s\n", total)
}
{{out}}
Total before tax: 22000000000000005.72
Tax: 1683000000000000.44
Total: 23683000000000006.16
Haskell
import Data.Fixed
import Text.Printf
type Percent = Centi
type Dollars = Centi
tax :: Percent -> Dollars -> Dollars
tax rate = MkFixed . round . (rate *)
printAmount :: String -> Dollars -> IO ()
printAmount name = printf "%-10s %20s\n" name . showFixed False
main :: IO ()
main = do
let subtotal = 4000000000000000 * 5.50 + 2 * 2.86
tx = tax 7.65 subtotal
total = subtotal + tx
printAmount "Subtotal" subtotal
printAmount "Tax" tx
printAmount "Total" total
{{out}}
$ ./currency
Subtotal 22000000000000005.72
Tax 1683000000000000.44
Total 23683000000000006.16
J
We use a naive implementation with arbitrary precision (rational) numbers:
require 'format/printf'
fmtD=: 0j2&": NB. format rational as decimal
Items=: ;: 'Hamburger Milkshake'
Quantities=: x: 4000000000000000 2
Prices=: x: 5.50 2.86
Tax_rate=: x: 0.0765
Values=: Quantities * Prices
Subtotal=: +/ Values
Tax=: Tax_rate * Subtotal
Total=: Subtotal + Tax
OutputTemplate=: noun define
Item Price Quantity Value
%9s %8s %20d %22s
%9s %8s %20d %22s
-------------------------------
Subtotal: %20s
Tax: %20s
Total: %20s
)
Vals=: (,Items ,. (fmtD&.> Prices) ,. (<"0 Quantities) ,. (fmtD&.> Values)) , fmtD&.> Subtotal,Tax,Total
OutputTemplate printf Vals
{{out}}
Item Price Quantity Value
Hamburger 5.50 4000000000000000 22000000000000000.00
Milkshake 2.86 2 5.72
-------------------------------
Subtotal: 22000000000000005.72
Tax: 1683000000000000.44
Total: 23683000000000006.16
(Note that if you ever get a bill like this in real life, you should question the person who gave it to you. And, possibly consider legal action and/or patronizing a different establishment. This is because (a) you did not order that many hamburgers, and (b) they did not deliver that many hamburgers, and (c) that much hamburger probably does not exist, and ...)
Java
import java.math.*;
import java.util.*;
public class Currency {
final static String taxrate = "7.65";
enum MenuItem {
Hamburger("5.50"), Milkshake("2.86");
private MenuItem(String p) {
price = new BigDecimal(p);
}
public final BigDecimal price;
}
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
MathContext mc = MathContext.DECIMAL128;
Map<MenuItem, BigDecimal> order = new HashMap<>();
order.put(MenuItem.Hamburger, new BigDecimal("4000000000000000"));
order.put(MenuItem.Milkshake, new BigDecimal("2"));
BigDecimal subtotal = BigDecimal.ZERO;
for (MenuItem it : order.keySet())
subtotal = subtotal.add(it.price.multiply(order.get(it), mc));
BigDecimal tax = new BigDecimal(taxrate, mc);
tax = tax.divide(new BigDecimal("100"), mc);
tax = subtotal.multiply(tax, mc);
System.out.printf("Subtotal: %20.2f%n", subtotal);
System.out.printf(" Tax: %20.2f%n", tax);
System.out.printf(" Total: %20.2f%n", subtotal.add(tax));
}
}
Subtotal: 22000000000000005.72
Tax: 1683000000000000.44
Total: 23683000000000006.16
JavaScript
const money = require('money-math')
let hamburgers = 4000000000000000
let hamburgerPrice = 5.50
let shakes = 2
let shakePrice = 2.86
let tax = 7.65
let hamburgerTotal = money.mul(hamburgers.toFixed(0), money.floatToAmount(hamburgerPrice))
let shakeTotal = money.mul(shakes.toFixed(0), money.floatToAmount(shakePrice))
let subTotal = money.add(hamburgerTotal, shakeTotal)
let taxTotal = money.percent(subTotal, tax)
let total = money.add(subTotal, taxTotal)
console.log('Hamburger Total:', hamburgerTotal)
console.log('Shake Total:', shakeTotal)
console.log('Sub Total:', subTotal)
console.log('Tax:', taxTotal)
console.log('Total:', total)
Julia
{{works with|Julia|1.2}}
using Printf
p = [big"5.50", big"2.86"]
q = [4000000000000000, 2]
tr = big"0.0765"
beftax = p' * q
tax = beftax * tr
afttax = beftax + tax
@printf " - tot. before tax: %20.2f \$\n" beftax
@printf " - tax: %20.2f \$\n" tax
@printf " - tot. after tax: %20.2f \$\n" afttax
{{out}}
- tot. before tax: 22000000000000005.72 $
- tax: 1683000000000000.44 $
- tot. after tax: 23683000000000006.16 $
Kotlin
// version 1.1.2
import java.math.BigDecimal
import java.math.MathContext
fun main(args: Array<String>) {
val mc = MathContext.DECIMAL128
val nHamburger = BigDecimal("4000000000000000", mc)
val pHamburger = BigDecimal("5.50")
val nMilkshakes = BigDecimal("2", mc)
val pMilkshakes = BigDecimal("2.86")
val taxRate = BigDecimal("0.0765")
val price = nHamburger * pHamburger + nMilkshakes * pMilkshakes
val tax = price * taxRate
val fmt = "%20.2f"
println("Total price before tax : ${fmt.format(price)}")
println("Tax thereon @ 7.65% : ${fmt.format(tax)}")
println("Total price after tax : ${fmt.format(price + tax)}")
}
{{out}}
Total price before tax : 22000000000000005.72
Tax thereon @ 7.65% : 1683000000000000.44
Total price after tax : 23683000000000006.16
M2000 Interpreter
This task written in M2000 Environment running on Wine 3.6, in a Linux Ubuntu Studio. M2000 environment is an ActiveX object, written with VB6, which use many types from [https://en.wikipedia.org/wiki/Variant_type COM Variant Type].
Module Currency_Task {
Locale 1033
Font "Courier New"
Form 80,32
\\Decimal type
hamburgers=4000000000000000@
\\ Currency type
hamburger_price=5.5#
milkshakes=2#
milkshake_price=2.86#
tax_rate=0.0765#
\\ Using Columns with variable width in console
PrHeadLine("Item","price","quantity", "value")
PrLine("hamburger",hamburger_price,hamburgers,hamburgers*hamburger_price)
PrLine("milkshake", milkshake_price,milkshakes,milkshakes*milkshake_price)
PrResults( "subtotal", hamburgers*hamburger_price+milkshakes*milkshake_price)
PrResults("tax", (hamburgers*hamburger_price+milkshakes*milkshake_price)*tax_rate)
\\ 1 is double by default we can use 1# or 1@
PrResults("total", (hamburgers*hamburger_price+milkshakes*milkshake_price)*(tax_rate+1))
\\ Using variables for partial calculations. They get type from expression result
h_p_q=hamburgers*hamburger_price
m_p_q=milkshakes*milkshake_price
\\ Using format$ to prepare final strings
Print format$("{0:15}{1:-8}{2:-25}{3:-25}","Item", "price", "quantity", "value")
Print format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","hamburger",hamburger_price,hamburgers, h_p_q)
Print format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","milkshake", milkshake_price,milkshakes,m_p_q)
Print format$("{0:-48}{1:2:-25}","subtotal", h_p_q+m_p_q)
Print format$("{0:-48}{1:2:-25}","tax", (h_p_q+m_p_q)*tax_rate)
Print format$("{0:-48}{1:2:-25}","total", (h_p_q+m_p_q)*(tax_rate+1))
\\ Another time to feed Document to export to clipboard
Document Doc$=format$("{0:15}{1:-8}{2:-25}{3:-25}","Item", "price", "quantity", "value")+{
}+format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","hamburger",hamburger_price,hamburgers, h_p_q)+{
}+format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","milkshake", milkshake_price,milkshakes,m_p_q)+{
}+format$("{0:-48}{1:2:-25}","subtotal", h_p_q+m_p_q)+{
}+format$("{0:-48}{1:2:-25}","tax", (h_p_q+m_p_q)*tax_rate)+{
}+format$("{0:-48}{1:2:-25}","total", (h_p_q+m_p_q)*(tax_rate+1))+{
}
clipboard Doc$
\\ one line user function definition
\\ x get type from passed value
Def ExpressionType$(x)=Type$(X)
\\ Check Expression final type
Print ExpressionType$(hamburgers)="Decimal"
Print ExpressionType$(milkshakes)="Currency"
Print ExpressionType$(h_p_q)="Decimal"
Print ExpressionType$(m_p_q)="Currency"
Print ExpressionType$((h_p_q+m_p_q)*tax_rate)="Decimal"
Print ExpressionType$((h_p_q+m_p_q)*(tax_rate+1))="Decimal"
Sub PrHeadLine(a$,b$,c$,d$)
Print Part $(1,15),a$,$(3,8),b$, $(3,25),c$, $(3,25),d$
Print
End Sub
Sub PrLine(a$,b,c,d)
Print Part $(1,15),a$,$("0.00"),$(3,8),b, $("0"),$(3,25),c,$("0.00"), $(3,25),d
Print
End Sub
Sub PrResults(a$,b)
Print Part $(3,48),a$,$("0.00"),$(3,25),b
Print
End Sub
}
Currency_Task
Optional with $ and thousands separator (a smaller version from above)
Module Currency_Task {
Locale 1033
Font "Courier New"
Form 80,32
hamburgers=4000000000000000@
hamburger_price=5.5#
milkshakes=2#
milkshake_price=2.86#
tax_rate=0.0765#
PrHeadLine("Item","price","quantity", "value")
PrLine("hamburger",hamburger_price,hamburgers,hamburgers*hamburger_price)
PrLine("milkshake", milkshake_price,milkshakes,milkshakes*milkshake_price)
PrResults( "subtotal", hamburgers*hamburger_price+milkshakes*milkshake_price)
PrResults("tax", (hamburgers*hamburger_price+milkshakes*milkshake_price)*tax_rate)
PrResults("total", (hamburgers*hamburger_price+milkshakes*milkshake_price)*(tax_rate+1))
h_p_q=hamburgers*hamburger_price
m_p_q=milkshakes*milkshake_price
Document Doc$=format$("{0:15}{1:-8}{2:-25}{3:-30}","Item", "price", "quantity", "value")+{
}+format$("{0:15}{1:-8}{2:-25}{3:-30}","hamburger",str$(hamburger_price,"$#,##0.00"),str$(hamburgers, "#,##0"), Str$(h_p_q,"$#,##0.00"))+{
}+format$("{0:15}{1:-8}{2:-25}{3:-30}","milkshake", str$(milkshake_price,"$#,##0.00"),Str$(milkshakes, "#,##0"), Str$(m_p_q,"$#,##0.00"))+{
}+format$("{0:-48}{1:-30}","subtotal", Str$(h_p_q+m_p_q,"$#,##0.00"))+{
}+format$("{0:-48}{1:-30}","tax", Str$((h_p_q+m_p_q)*tax_rate,"$#,##0.00"))+{
}+format$("{0:-48}{1:-30}","total", Str$((h_p_q+m_p_q)*(tax_rate+1),"$#,##0.00"))+{
}
clipboard Doc$
Sub PrHeadLine(a$,b$,c$,d$)
Print Part $(1,15),a$,$(3,8),b$, $(3,25),c$, $(3,30),d$
Print
End Sub
Sub PrLine(a$,b,c,d)
Print Part $(1,15),a$,$("$#,###.00"),$(3,8),b, $("#,##0"),$(3,25),c,$("$#,###.00"), $(3,30),d
Print
End Sub
Sub PrResults(a$,b)
Print Part $(3,48),a$,$("$#,###.00"),$(3,30),b
Print
End Sub
}
Currency_Task
{{out}}
Item price quantity value hamburger 5.50 4000000000000000 22000000000000000.00 milkshake 2.86 2 5.72 subtotal 22000000000000005.72 tax 1683000000000000.44 total 23683000000000006.16 From Optional Item price quantity value hamburger $5.50 4,000,000,000,000,000 $22,000,000,000,000,000.00 milkshake $2.86 2 $5.72 subtotal $22,000,000,000,000,005.72 tax $1,683,000,000,000,000.44 total $23,683,000,000,000,006.16## Maple ```Maple Digits := 50; tax := .0765; burgersquantity := 4000000000000000; burgersprice := 5.50; burgerscost := burgersquantity * burgersprice; milkshakesquantity := 2; milkshakesprice := 2.86; milkshakescost := milkshakesquantity * milkshakesprice; total := burgerscost + milkshakescost; printf("%.2f\n",total); totaltax := total * tax; printf("%.2f\n",totaltax); totalprice := totaltax + total; printf("%.2f\n",totalprice); ``` {{out}} ```txt 22000000000000005.72 1683000000000000.44 23683000000000006.16 ``` ## OCaml Using the [https://github.com/janestreet/bignum Bignum] library. ```ocaml #require "bignum" ;; let p1 = Bignum.((of_string "4000000000000000") * (of_float_decimal 5.50)) ;; let p2 = Bignum.((of_int 2) * (of_float_decimal 2.86)) ;; let r1 = Bignum.(p1 + p2) ;; let r2 = Bignum.(r1 * (of_float_decimal (7.65 /. 100.))) ;; let r3 = Bignum.(r1 + r2) ;; let my_to_string v = Bignum.(v |> round_decimal ~dir:`Nearest ~digits:2 |> to_string_hum ~decimals:2) ;; let () = Printf.printf "before tax: %s\n" (my_to_string r1); Printf.printf "tax: %s\n" (my_to_string r2); Printf.printf "total: %s\n" (my_to_string r3); ;; ``` {{out}} ```txt $ opam install bignum $ opam install utop $ eval $(opam env) $ utop currency.ml before tax: 22000000000000005.72 tax: 1683000000000000.44 total: 23683000000000006.16 ``` ## Perl ```perl use Math::Decimal qw(dec_canonise dec_add dec_mul dec_rndiv_and_rem); @check = ( [