README.md (4708B)
1 # Decimal 2 3 [![Build Status](https://travis-ci.org/ericmj/decimal.svg?branch=master)](https://travis-ci.org/ericmj/decimal) 4 5 Arbitrary precision decimal arithmetic. 6 7 ## Usage 8 9 Add Decimal as a dependency in your `mix.exs` file. 10 11 ```elixir 12 def deps do 13 [{:decimal, "~> 2.0"}] 14 end 15 ``` 16 17 After you are done, run `mix deps.get` in your shell to fetch and compile Decimal. Start an interactive Elixir shell with `iex -S mix`. 18 19 ```elixir 20 iex> alias Decimal, as: D 21 iex> D.add(6, 7) 22 #Decimal<13> 23 iex> D.div(1, 3) 24 #Decimal<0.333333333> 25 iex> D.new("0.33") 26 #Decimal<0.33> 27 ``` 28 29 ## Examples 30 31 ### Using the context 32 33 The context specifies the maximum precision of the result of calculations and 34 the rounding algorithm if the result has a higher precision than the specified 35 maximum. It also holds the list of set of trap enablers and the currently set 36 flags. 37 38 The context is stored in the process dictionary, this means that you don't have 39 to pass the context around explicitly and the flags will be updated 40 automatically. 41 42 The context is accessed with `Decimal.Context.get/0` and set with 43 `Decimal.Context.set/1`. It can also be temporarily set with 44 `Decimal.Context.with/2`. 45 46 ```elixir 47 iex> D.Context.get() 48 %Decimal.Context{flags: [:rounded, :inexact], precision: 9, rounding: :half_up, 49 traps: [:invalid_operation, :division_by_zero]} 50 iex> D.Context.with(%D.Context{precision: 2}, fn -> IO.inspect D.Context.get() end) 51 %Decimal.Context{flags: [], precision: 2, rounding: :half_up, 52 traps: [:invalid_operation, :division_by_zero]} 53 %Decimal.Context{flags: [], precision: 2, rounding: :half_up, 54 traps: [:invalid_operation, :division_by_zero]} 55 iex> D.Context.set(%D.Context{D.Context.get() | traps: []}) 56 :ok 57 iex> D.Context.get() 58 %Decimal.Context{flags: [:rounded, :inexact], precision: 9, rounding: :half_up, 59 traps: []} 60 ``` 61 62 ### Precision and rounding 63 64 The precision is used to limit the amount of decimal digits in the coefficient: 65 66 ```elixir 67 iex> D.Context.set(%D.Context{D.Context.get() | precision: 9}) 68 :ok 69 iex> D.div(100, 3) 70 #Decimal<33.3333333> 71 iex> D.Context.set(%D.Context{D.Context.get() | precision: 2}) 72 :ok 73 iex> D.div(100, 3) 74 #Decimal<33> 75 ``` 76 77 The rounding algorithm specifies how the result of an operation shall be rounded 78 when it get be represented with the current precision: 79 80 ```elixir 81 iex> D.Context.set(%D.Context{D.Context.get() | rounding: :half_up}) 82 :ok 83 iex> D.div(31, 2) 84 #Decimal<16> 85 iex> D.Context.set(%D.Context{D.Context.get() | rounding: :floor}) 86 :ok 87 iex> D.div(31, 2) 88 #Decimal<15> 89 ``` 90 91 ### Comparisons 92 93 Using compare operators (`<`, `=`, `>`) directly with two decimals may not return 94 the correct result. Instead use comparison functions. 95 96 ```elixir 97 iex> D.compare(-1, 0) 98 :lt 99 iex> D.compare(0, -1) 100 :gt 101 iex> D.compare(0, 0) 102 :eq 103 104 iex> D.equal?(-1, 0) 105 false 106 iex> D.equal?(0, "0.0") 107 true 108 ``` 109 110 ### Flags and trap enablers 111 112 When an exceptional condition is signalled its flag is set in the context and if 113 if the trap enabler is set `Decimal.Error` will be raised. 114 115 ```elixir 116 iex> D.Context.set(%D.Context{D.Context.get() | rounding: :floor, precision: 2}) 117 :ok 118 iex> D.Context.get().traps 119 [:invalid_operation, :division_by_zero] 120 iex> D.Context.get().flags 121 [] 122 iex> D.div(31, 2) 123 #Decimal<15> 124 iex> D.Context.get().flags 125 [:inexact, :rounded] 126 ``` 127 128 `:inexact` and `:rounded` were signaled above because the result of the 129 operation was inexact given the context's precision and had to be rounded to fit 130 the precision. `Decimal.Error` was not raised because the signals' trap enablers 131 weren't set. We can, however, set the trap enabler if we what this condition to 132 raise. 133 134 ```elixir 135 iex> D.Context.set(%D.Context{D.Context.get() | traps: D.Context.get().traps ++ [:inexact]}) 136 :ok 137 iex> D.div(31, 2) 138 ** (Decimal.Error) 139 ``` 140 141 The default trap enablers, such as `:division_by_zero` can be unset: 142 143 ```elixir 144 iex> D.Context.get().traps 145 [:invalid_operation, :division_by_zero] 146 iex> D.div(42, 0) 147 ** (Decimal.Error) 148 iex> D.Context.set(%D.Context{D.Context.get() | traps: [], flags: []}) 149 :ok 150 iex> D.div(42, 0) 151 #Decimal<Infinity> 152 iex> D.Context.get().flags 153 [:division_by_zero] 154 ``` 155 156 ### Mitigating rounding errors 157 158 TODO 159 160 ## License 161 162 Copyright 2013 Eric Meadows-Jönsson 163 164 Licensed under the Apache License, Version 2.0 (the "License"); 165 you may not use this file except in compliance with the License. 166 You may obtain a copy of the License at 167 168 http://www.apache.org/licenses/LICENSE-2.0 169 170 Unless required by applicable law or agreed to in writing, software 171 distributed under the License is distributed on an "AS IS" BASIS, 172 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 173 See the License for the specific language governing permissions and 174 limitations under the License.