Numbers -- A generic wrapper to use *any* custom Numeric type in Elixir!
Numbers is a tiny Elixir package that facilitates the creation of libraries that want to be able to use any kind of Numberlike type.
Some known custom numeric types that implement Numbers' protocols:
Just add one (or multiple) of these libraries to your project, together with Numbers, and you're good to go!
Starting at version 5, Numbers contains a set of protocols that can be independently implemented for your data structures.
Each protocol maps to a single arithmetical operation that your data structure might support.
Because protocols are used, Numbers can dispatch quite fast! Also, Numbers does not restrict your modules to any special naming schemes (as was the case with older versions of Numbers that used a Behaviour).
The following operations are supported:
add
for addition, by implementing Numbers.Protocols.Addition
.sub
for subtraction, by implementing Numbers.Protocols.Subtraction
.mult
for multiplication, by implementing Numbers.Protocols.Multiplication
.div
for division, by implementing Numbers.Protocols.Division
.minus
for unary minus (negation), by implementing Numbers.Protocols.Minus
.abs
to calculate the absolute value of a number, by implementing Numbers.Protocols.Absolute
.pow
for calculating integer powers, by implementing Numbers.Protocols.Exponentiation
. A special helper in Numbers.Helpers.pow_by_sq
can be used inside this implementation to automatically make use of the 'Exponentiation by Squaring' algorithm.to_float
for (possibly lossy) conversion to the built-in Float datatype, by implementing Numbers.Protocols.ToFloat
.Numbers does not automatically transform numbers from one type to another if one of the functions is called with two different types.
Frequently you do want to use other data types together with your custom data type. For this, a custom coercion can be specified,
using Coerce.defcoercion
as exposed by the Coerce
library that Numbers
depends on.
The only coercion that ships with Numbers itself, is a coercion of Integers to Floats, meaning that they work the same way as when using the standard library math functions with these types.
You can opt-in to overloaded +, -, *, /
operators by calling use Numbers, overload_operators: true
.
This allows you to use these inline operators for all other Numberlike types.
The library uses a conditional compilation technique to make sure that you will still be able to use the operators inside guards for built-in integers and floats.
As example consider:
defmodule An.Example do
use Numbers, overload_operators: true
def foo(a, b) when a + b < 10 do # Uses the normal guard-safe '+' operator (e.g. Kernel.+/2)
42
end
def foo(c, d) do
c + d # Uses the overloaded '+' operator.
end
end
Using built-in numbers:
iex> alias Numbers, as: N
iex> N.add(1, 2)
3
iex> N.mult(3,5)
15
iex> N.mult(1.5, 100)
150.0
Using Decimals: (requires the Decimal library.)
iex> alias Numbers, as: N
iex> d = Decimal.new(2)
iex> N.div(d, 10)
#Decimal<0.2>
iex> small_number = N.div(d, 1234)
#Decimal<0.001620745542949756888168557536>
iex> N.pow(small_number, 100)
The package can be installed as:
numbers
to your list of dependencies in mix.exs
:def deps do
[{:numbers, "~> 5.2"}]
end
:decimal
dependency to now allow both version 1.x
as well as version 2.x
.:decimal
dependency to 1.9
or newer, and replaces deprecated Decimal.minus/1
call with Decimal.negate/1
mix.exs
to use extra_applications
rather than manually overridding applications
. This drops support for now very old versions of Elixir (< v1.4) but ensures proper support with Elixir v1.11 and beyond.a - 1 = 10
).Decimal
dependency version less specific to play nicer with other libraries :-).Coerce
library. Announcement post
Numeric
to Numbers.Numeric
, to follow proper code organization conventions.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.mul
-> mult
.