@@ -40,6 +40,45 @@ defmodule Decimal do
4040 according to the specification, return a number that "underflows" 0 is returned
4141 instead of Etiny. This may happen when dividing a number with infinity.
4242 Additionally, overflow, underflow and clamped may never be signalled.
43+
44+ ## Protocol Implementations
45+
46+ `Decimal` implements the following protocols:
47+
48+ ### `Inspect`
49+
50+ iex> inspect(Decimal.new("1.00"))
51+ "Decimal.new(\\ "1.00\\ ")"
52+
53+ ### `String.Chars`
54+
55+ iex> to_string(Decimal.new("1.00"))
56+ "1.00"
57+
58+ ### `JSON.Encoder`
59+
60+ _(If running Elixir 1.18+.)_
61+
62+ By default, decimals are encoded as strings to preserve precision:
63+
64+ iex> JSON.encode!(Decimal.new("1.00"))
65+ "\\ "1.00\\ ""
66+
67+ To change that, pass a custom encoder to `JSON.encode!/2`. The following encodes
68+ decimals as floats:
69+
70+ iex> encoder = fn
71+ ...> %Decimal{} = decimal, _encoder ->
72+ ...> decimal |> Decimal.to_float() |> :json.encode_float()
73+ ...>
74+ ...> other, encoder ->
75+ ...> JSON.protocol_encode(other, encoder)
76+ ...> end
77+ ...>
78+ iex> JSON.encode!(%{x: Decimal.new("1.00")}, encoder)
79+ "{\\ "x\\ ":1.0}"
80+
81+ Note: `Decimal.to_float/1` crashes on infinite and NaN decimals.
4382 """
4483
4584 import Bitwise
@@ -1588,7 +1627,7 @@ defmodule Decimal do
15881627 @ doc """
15891628 Returns the decimal represented as an integer.
15901629
1591- Fails when loss of precision will occur.
1630+ Raises when loss of precision will occur.
15921631
15931632 ## Examples
15941633
@@ -1623,28 +1662,30 @@ defmodule Decimal do
16231662 @ doc """
16241663 Returns the decimal converted to a float.
16251664
1626- The returned float may have lower precision than the decimal. Fails if
1627- the decimal cannot be converted to a float.
1665+ The returned float may have lower precision than the decimal.
1666+
1667+ Raises if the decimal cannot be converted to a float.
16281668
16291669 ## Examples
16301670
16311671 iex> Decimal.to_float(Decimal.new("1.5"))
16321672 1.5
1673+
16331674 iex> Decimal.to_float(Decimal.new("-1.79769313486231581e308"))
16341675 ** (Decimal.Error) : negative number smaller than DBL_MAX: Decimal.new("-1.79769313486231581E+308")
16351676
1636-
16371677 iex> Decimal.to_float(Decimal.new("-1.79769313486231581e308"))
16381678 ** (Decimal.Error) : negative number smaller than DBL_MAX: Decimal.new("-1.79769313486231581E+308")
16391679
1640-
16411680 iex> Decimal.to_float(Decimal.new("2.22507385850720139e-308"))
16421681 ** (Decimal.Error) : number smaller than DBL_MIN: Decimal.new("2.22507385850720139E-308")
16431682
1644-
16451683 iex> Decimal.to_float(Decimal.new("-2.22507385850720139e-308"))
16461684 ** (Decimal.Error): negative number bigger than DBL_MIN: Decimal.new(\" -2.22507385850720139E-308\" )
16471685
1686+ iex> Decimal.to_float(Decimal.new("inf"))
1687+ ** (ArgumentError) Decimal.new("Infinity") cannot be converted to float
1688+
16481689 """
16491690 @ spec to_float ( t ) :: float
16501691 def to_float ( % Decimal { coef: coef } = decimal ) when is_integer ( coef ) do
@@ -1669,6 +1710,10 @@ defmodule Decimal do
16691710 end
16701711 end
16711712
1713+ def to_float ( % Decimal { } = decimal ) do
1714+ raise ArgumentError , "#{ inspect ( decimal ) } cannot be converted to float"
1715+ end
1716+
16721717 @ doc """
16731718 Returns the scale of the decimal.
16741719
0 commit comments