1
+ import Kernel , except: [ round: 1 ]
2
+
1
3
defmodule Float do
2
4
@ moduledoc """
3
5
Functions for working with floating point numbers.
@@ -98,9 +100,13 @@ defmodule Float do
98
100
99
101
@ doc """
100
102
Rounds a float to the largest integer less than or equal to `num`.
103
+
101
104
Floor also accepts a precision to round a floating point value down
102
105
to an arbitrary number of fractional digits (between 0 and 15).
103
106
107
+ This function always returns floats. One may use `Kernel.trunc/1` to
108
+ truncate the result to an integer afterwards.
109
+
104
110
## Examples
105
111
106
112
iex> Float.floor(34.25)
@@ -113,25 +119,24 @@ defmodule Float do
113
119
34.25
114
120
115
121
"""
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
128
129
end
129
130
130
131
@ doc """
131
132
Rounds a float to the largest integer greater than or equal to `num`.
133
+
132
134
Ceil also accepts a precision to round a floating point value down to
133
135
an arbitrary number of fractional digits (between 0 and 15).
134
136
137
+ This function always returns floats. One may use `Kernel.trunc/1` to
138
+ truncate the result to an integer afterwards.
139
+
135
140
## Examples
136
141
137
142
iex> Float.ceil(34.25)
@@ -144,25 +149,23 @@ defmodule Float do
144
149
34.26
145
150
146
151
"""
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
160
159
end
161
160
162
161
@ doc """
163
162
Rounds a floating point value to an arbitrary number of fractional digits
164
163
(between 0 and 15).
165
164
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
+
166
169
## Examples
167
170
168
171
iex> Float.round(5.5674, 3)
@@ -178,9 +181,15 @@ defmodule Float do
178
181
-5.568
179
182
180
183
"""
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
184
193
end
185
194
186
195
@ doc """
@@ -260,10 +269,6 @@ defmodule Float do
260
269
:erlang . float_to_binary ( float , expand_compact ( options ) )
261
270
end
262
271
263
- defp calculate_precision ( num , variance , precision ) do
264
- num + ( variance / :math . pow ( 10 , precision ) )
265
- end
266
-
267
272
defp expand_compact ( [ { :compact , false } | t ] ) , do: expand_compact ( t )
268
273
defp expand_compact ( [ { :compact , true } | t ] ) , do: [ :compact | expand_compact ( t ) ]
269
274
defp expand_compact ( [ h | t ] ) , do: [ h | expand_compact ( t ) ]
0 commit comments