Packages

Numbers dispatches on any numeric type that follows the `Numeric` behaviour. This allows you to create composite types working with _any_ numeric type (Decimal, Ratio, Tensor, ComplexNum, ???)!

Current section

20 Versions

Jump to

Compare versions

7 files changed
+154 additions
-8 deletions
  @@ -66,6 +66,8 @@ iex> N.mult(1.5, 100)
66 66 Using Decimals: (requires the [Decimal](https://hex.pm/packages/decimal) library.)
67 67
68 68 ```elixir
69 + iex> alias Numbers, as: N
70 +
69 71 iex> d = Decimal.new(2)
70 72 iex> N.div(d, 10)
71 73 #Decimal<0.2>
  @@ -84,13 +86,14 @@ The package can be installed as:
84 86
85 87 ```elixir
86 88 def deps do
87 - [{:numbers, "~> 5.0.0"}]
89 + [{:numbers, "~> 5.0.1"}]
88 90 end
89 91 ```
90 92
91 93 ## Changelog
92 94
93 - - 5.0.0 MAJOR OVERHAUL: New implementation based on a set of Protocols. Should be a lot faster and easier on implementers. Also uses a new method to perform coercions based on the `Coerce` library.
95 + - 5.0.1 Possibility to import overloaded operator variants. Also, greatly improved documentation.
96 + - 5.0.0 MAJOR OVERHAUL: New implementation based on a set of Protocols. Should be a lot faster and easier on implementers. Also uses a new method to perform coercions based on the `Coerce` library. [Announcement post](https://elixirforum.com/t/numbers-a-generic-wrapper-to-use-any-custom-numeric-type/2846/7)
94 97 - 4.0.0 Breaking change: Move `Numeric` to `Numbers.Numeric`, to follow proper code organization conventions.
95 98 - 3.0.1 Improved README
96 99 - 3.0.0 Remove public `Numbers.coerce/2` function, as it had confused naming and very limited use. Added optional `Numeric.coerce/2` callback (which works very different from the old `Numbers.coerce/2` function) which is now used underwater when coercion should happen.
  @@ -7,9 +7,9 @@
7 7 [<<"lib/numbers.ex">>,<<"lib/numbers/helper.ex">>,
8 8 <<"lib/numbers/implementations/decimal.ex">>,
9 9 <<"lib/numbers/implementations/float.ex">>,
10 - <<"lib/numbers/implementations/integer.ex">>,<<"lib/numbers/protocols.ex">>,
11 - <<"lib/numbers_old.exs">>,<<"lib/numeric.exs">>,<<"mix.exs">>,
12 - <<"README.md">>,<<"LICENSE">>]}.
10 + <<"lib/numbers/implementations/integer.ex">>,<<"lib/numbers/operators.ex">>,
11 + <<"lib/numbers/protocols.ex">>,<<"lib/numbers_old.exs">>,
12 + <<"lib/numeric.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>]}.
13 13 {<<"licenses">>,[<<"MIT">>]}.
14 14 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/Qqwy/elixir_number/">>}]}.
15 15 {<<"maintainers">>,[<<"Wiebe-Marten Wijnja/Qqwy">>]}.
  @@ -23,4 +23,4 @@
23 23 {<<"name">>,<<"decimal">>},
24 24 {<<"optional">>,true},
25 25 {<<"requirement">>,<<"~> 1.3.0">>}]]}.
26 - {<<"version">>,<<"5.0.0-rc0">>}.
26 + {<<"version">>,<<"5.0.1">>}.
  @@ -1,4 +1,65 @@
1 1 defmodule Numbers do
2 + @moduledoc """
3 + Allows you to use arithmetical operations on _any_ type
4 + that implements the proper protocols.
5 +
6 + For each arithmetical operation, a different protocol is used
7 + so that types for which only a subset of these operations makes sense
8 + can still work with those.
9 +
10 + ## Basic Usage
11 +
12 + Usually, `Numbers` is used in another module by using
13 + `alias Numbers, as: N`, followed by calling the functions using
14 + this aliased but still descriptive syntax:
15 + `total_price = N.mult(N.add(price, fee), vat)`
16 +
17 + Because `Numbers` dispatches based on protocol definitions,
18 + you only need to swap what kind of arguments are used
19 + to change the type of the result.
20 +
21 +
22 + ## Overloaded Operators
23 +
24 + As explicit opt-in functionality, `Numbers` will add overloaded
25 + operators to your module, if you write `use Numbers, overload_operators: true`
26 +
27 + This will alter `a + b`, `a - b`, `a * b`, `a / b`, `-a` and `abs(a)` to
28 + dispatch to the corresponding functions in the `Numbers` module.
29 +
30 + Do note that these overloaded operator versions are _not_ allowed in guard tests,
31 + which is why this functionality is only provided as an opt-in option to use
32 + when an algorithm would be too unreadable without it.
33 +
34 +
35 + ## Examples:
36 +
37 + Using built-in numbers:
38 +
39 + iex> alias Numbers, as: N
40 + iex> N.add(1, 2)
41 + 3
42 + iex> N.mult(3,5)
43 + 15
44 + iex> N.mult(1.5, 100)
45 + 150.0
46 +
47 + Using Decimals: (requires the [Decimal](https://hex.pm/packages/decimal) library.)
48 +
49 + iex> alias Numbers, as: N
50 + iex> d = Decimal.new(2)
51 + iex> N.div(d, 10)
52 + #Decimal<0.2>
53 + iex> small_number = N.div(d, 1234)
54 + #Decimal<0.001620745542949756888168557536>
55 + iex> N.pow(small_number, 100)
56 + #Decimal<9.364478495445313580679473524E-280>
57 +
58 + ## Defining your own Numbers implementations
59 +
60 + See `Numbers.Protocols` for a full explanation on how to do this.
61 + """
62 +
2 63 import Kernel, except: [div: 2]
3 64
4 65 @type t :: any
  @@ -91,4 +152,25 @@ defmodule Numbers do
91 152 """
92 153 @spec to_float(t) :: {:ok, t_as_float :: float} | :error
93 154 defdelegate to_float(num), to: Numbers.Protocols.ToFloat
155 +
156 +
157 + defmacro __using__(opts) do
158 + if opts[:overload_operators] != true do
159 + raise """
160 + `use Numbers` called without `overload_operators: true` option.
161 +
162 + Either make the exporting of operators explicit by writing
163 + `use Numbers, overload_operators: true`
164 + or if you do not want the overridden operators,
165 + simply use Numbers directly, and optionally
166 + alias it, using:
167 + `alias Numbers, as: N`.
168 + """
169 + else
170 + quote do
171 + import Kernel, except: [abs: 1, *: 2, /: 2, -: 2, -: 1, +: 2]
172 + import Numbers.Operators
173 + end
174 + end
175 + end
94 176 end
  @@ -1,4 +1,9 @@
1 1 defmodule Numbers.Helper do
2 + @moduledoc """
3 + Helper functions that might make the implementation
4 + of Numbers for your own numberlike types easier.
5 + """
6 +
2 7 @doc """
3 8 Performs 'Exponentiation by Squaring',
4 9 which is a reasonably fast algorithm to compute integer powers,
  @@ -0,0 +1,15 @@
1 + defmodule Numbers.Operators do
2 + # Do not import this module directly.
3 + # Instead, use `use Numbers, override_operators: true`
4 + # which will import this module's functions properly.
5 + @moduledoc false
6 +
7 + defdelegate a + b, to: Numbers, as: :add
8 + defdelegate a - b, to: Numbers, as: :sub
9 + defdelegate a * b, to: Numbers, as: :mult
10 + defdelegate a / b, to: Numbers, as: :div
11 + defdelegate -a, to: Numbers, as: :minus
12 + defdelegate abs(a), to: Numbers, as: :abs
13 +
14 + defdelegate pow(a, b), to: Numbers
15 + end
Loading more files…