1+ import Kernel , except: [ round: 1 ]
2+
13defmodule Float do
24 @ moduledoc """
35 Functions for working with floating point numbers.
@@ -98,9 +100,13 @@ defmodule Float do
98100
99101 @ doc """
100102 Rounds a float to the largest integer less than or equal to `num`.
103+
101104 Floor also accepts a precision to round a floating point value down
102105 to an arbitrary number of fractional digits (between 0 and 15).
103106
107+ This function always returns floats. One may use `Kernel.trunc/1` to
108+ truncate the result to an integer afterwards.
109+
104110 ## Examples
105111
106112 iex> Float.floor(34.25)
@@ -113,25 +119,24 @@ defmodule Float do
113119 34.25
114120
115121 """
116- @ spec floor ( float ) :: float
117- def floor ( num ) when is_float ( num ) do
118- truncated = :erlang . trunc ( num )
119- case :erlang . abs ( num - truncated ) do
120- x when x > 0 and num < 0 -> truncated - 1.0
121- _ -> truncated + 0.0
122- end
123- end
124-
125- @ spec floor ( float , integer ) :: float
126- def floor ( num , precision ) when is_float ( num ) do
127- calculate_precision ( num , - 0.5 , precision ) |> round ( precision )
122+ @ spec floor ( float , 0 .. 15 ) :: float
123+ def floor ( number , precision \\ 0 ) when is_float ( number ) and precision in 0 .. 15 do
124+ power = power_of_10 ( precision )
125+ number = number * power
126+ truncated = trunc ( number )
127+ variance = if number - truncated < 0 , do: - 1.0 , else: 0.0
128+ ( truncated + variance ) / power
128129 end
129130
130131 @ doc """
131132 Rounds a float to the largest integer greater than or equal to `num`.
133+
132134 Ceil also accepts a precision to round a floating point value down to
133135 an arbitrary number of fractional digits (between 0 and 15).
134136
137+ This function always returns floats. One may use `Kernel.trunc/1` to
138+ truncate the result to an integer afterwards.
139+
135140 ## Examples
136141
137142 iex> Float.ceil(34.25)
@@ -144,25 +149,23 @@ defmodule Float do
144149 34.26
145150
146151 """
147-
148- @ spec ceil ( float ) :: float
149- def ceil ( num ) when is_float ( num ) do
150- truncated = :erlang . trunc ( num )
151- case :erlang . abs ( num - truncated ) do
152- x when x > 0 and num > 0 -> truncated + 1.0
153- _ -> truncated + 0.0
154- end
155- end
156-
157- @ spec ceil ( float , integer ) :: float
158- def ceil ( num , precision ) when is_float ( num ) do
159- calculate_precision ( num , 0.5 , precision ) |> round ( precision )
152+ @ spec ceil ( float , 0 .. 15 ) :: float
153+ def ceil ( number , precision \\ 0 ) when is_float ( number ) and precision in 0 .. 15 do
154+ power = power_of_10 ( precision )
155+ number = number * power
156+ truncated = trunc ( number )
157+ variance = if number - truncated > 0 , do: 1.0 , else: 0.0
158+ ( truncated + variance ) / power
160159 end
161160
162161 @ doc """
163162 Rounds a floating point value to an arbitrary number of fractional digits
164163 (between 0 and 15).
165164
165+ This function only accepts floats and returns floats. Use `Kernel.round/1`
166+ if you want a function that accepts both floats and integers and always
167+ returns an integer.
168+
166169 ## Examples
167170
168171 iex> Float.round(5.5674, 3)
@@ -178,9 +181,15 @@ defmodule Float do
178181 -5.568
179182
180183 """
181- @ spec round ( float , integer ) :: float
182- def round ( number , precision ) when is_float ( number ) and is_integer ( precision ) and precision in 0 .. 15 do
183- Kernel . round ( number * :math . pow ( 10 , precision ) ) / :math . pow ( 10 , precision )
184+ @ spec round ( float , 0 .. 15 ) :: float
185+ def round ( number , precision \\ 0 ) when is_float ( number ) and precision in 0 .. 15 do
186+ power = power_of_10 ( precision )
187+ Kernel . round ( number * power ) / power
188+ end
189+
190+ Enum . reduce 0 .. 15 , 1 , fn x , acc ->
191+ defp power_of_10 ( unquote ( x ) ) , do: unquote ( acc )
192+ acc * 10
184193 end
185194
186195 @ doc """
@@ -260,10 +269,6 @@ defmodule Float do
260269 :erlang . float_to_binary ( float , expand_compact ( options ) )
261270 end
262271
263- defp calculate_precision ( num , variance , precision ) do
264- num + ( variance / :math . pow ( 10 , precision ) )
265- end
266-
267272 defp expand_compact ( [ { :compact , false } | t ] ) , do: expand_compact ( t )
268273 defp expand_compact ( [ { :compact , true } | t ] ) , do: [ :compact | expand_compact ( t ) ]
269274 defp expand_compact ( [ h | t ] ) , do: [ h | expand_compact ( t ) ]
0 commit comments