This library provides a :decimal module that has the same functions (API,
interface) as the good^H^H^H^Hbad old erlang_decimal library, but it is
just an interface to the Elixir Decimal library.
The old erlang_decimal used 2-tuples with integers in it to represent
numbers, while the Elixir decimal uses structs. By using this library, the
module :decimal serves as the old API, and the module Decimal as the new
one. Unfortunately, the application names clash in the package decimal and
erlang_decimal, so you cannot use them at once, but fake_decimal plays
nicely with the Elixir decimal.
If there's a legacy application that calls into :decimal, but you also need
the Elixir decimal library in your app, you may be able to provide the old
API for the legacy app by using fake_decimal.
The functions where rounding semantics matter (round/3, divide/3,
sqrt/2, cmp/3, fast_cmp/2, to_binary/1,2) reproduce the original
erlang_decimal algorithms exactly: precision counts fractional digits
(decimal places, not significant digits), and the round_half_up /
round_half_down modes decide based on the first discarded digit only,
just like the original.
Parsing and formatting live in :decimal_conv, a direct port of the
original's second module, so strings, charlists and floats convert exactly as
they did before — including raising badarg on malformed input.
Like the original, the opts maps of to_decimal/2, divide/3, sqrt/2
and cmp/3 must carry both :precision and :rounding whenever the call
actually needs them; a partial map raises FunctionClauseError.
Deviations from erlang_decimal
add/2,sub/2andmult/2results are normalized:add({1, 0}, {9, 0})returns{1, 1}where the original returns{10, 0}. The two tuples are numerically equal (cmp/3returns0andreduce/1maps both to the same tuple), but code that pattern-matches exact tuples may see a different — equivalent — representation.Wherever the original accepts only
{coef, exp}tuples, this module also accepts the old{sign, coef, exp}format, ElixirDecimalstructs, integers, floats, strings and charlists. The original raisesFunctionClauseErrorfor those; accepting them cannot break code that worked against the original.
Summary
Types
@type opts() :: %{ optional(:precision) => non_neg_integer(), optional(:rounding) => rounding_algorithm() }
@type rounding_algorithm() ::
:round_floor
| :round_ceiling
| :round_half_up
| :round_half_down
| :round_down
Functions
@spec abs(value()) :: decimal()
@spec add(value(), value()) :: decimal()
@spec cmp(value(), value(), opts()) :: -1 | 0 | 1
@spec fast_cmp(value(), value()) :: -1 | 0 | 1
@spec is_zero(value()) :: boolean()
@spec minus(value()) :: decimal()
@spec mult(value(), value()) :: decimal()
@spec reduce(value()) :: decimal()
@spec round(rounding_algorithm(), value(), non_neg_integer()) :: decimal()
@spec sub(value(), value()) :: decimal()
@spec to_binary(value()) :: binary()
@spec to_binary(value(), :decimal_conv.binary_opts()) :: binary()
@spec to_decimal(value()) :: decimal()