Skip to content

Commit 583a4ec

Browse files
Johnny Winnhashrocketeer
authored andcommitted
Add precision to Float.ceil/1 & Float.floor/1
1 parent bba4f1b commit 583a4ec

File tree

2 files changed

+67
-44
lines changed

2 files changed

+67
-44
lines changed

lib/elixir/lib/float.ex

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,54 +98,67 @@ defmodule Float do
9898

9999
@doc """
100100
Rounds a float to the largest integer less than or equal to `num`.
101+
Floor also accepts a precision to round a floating point value down
102+
to an arbitrary number of fractional digits (between 0 and 15).
101103
102104
## Examples
103105
104-
iex> Float.floor(34)
105-
34
106-
107106
iex> Float.floor(34.25)
108-
34
107+
34.0
109108
110109
iex> Float.floor(-56.5)
111-
-57
110+
-57.0
111+
112+
iex> Float.floor(34.253, 2)
113+
34.25
112114
113115
"""
114-
@spec floor(float | integer) :: integer
115-
def floor(num) when is_integer(num), do: num
116+
@spec floor(float) :: float
116117
def floor(num) when is_float(num) do
117118
truncated = :erlang.trunc(num)
118119
case :erlang.abs(num - truncated) do
119-
x when x > 0 and num < 0 -> truncated - 1
120-
_ -> truncated
120+
x when x > 0 and num < 0 -> truncated - 1.0
121+
_ -> truncated + 0.0
121122
end
122123
end
123124

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)
128+
end
129+
124130
@doc """
125131
Rounds a float to the largest integer greater than or equal to `num`.
132+
Ceil also accepts a precision to round a floating point value down to
133+
an arbitrary number of fractional digits (between 0 and 15).
126134
127135
## Examples
128136
129-
iex> Float.ceil(34)
130-
34
131-
132137
iex> Float.ceil(34.25)
133-
35
138+
35.0
134139
135140
iex> Float.ceil(-56.5)
136-
-56
141+
-56.0
142+
143+
iex> Float.ceil(34.253, 2)
144+
34.26
137145
138146
"""
139-
@spec ceil(float | integer) :: integer
140-
def ceil(num) when is_integer(num), do: num
147+
148+
@spec ceil(float) :: float
141149
def ceil(num) when is_float(num) do
142150
truncated = :erlang.trunc(num)
143151
case :erlang.abs(num - truncated) do
144-
x when x > 0 and num > 0 -> truncated + 1
145-
_ -> truncated
152+
x when x > 0 and num > 0 -> truncated + 1.0
153+
_ -> truncated + 0.0
146154
end
147155
end
148156

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)
160+
end
161+
149162
@doc """
150163
Rounds a floating point value to an arbitrary number of fractional digits
151164
(between 0 and 15).
@@ -247,6 +260,10 @@ defmodule Float do
247260
:erlang.float_to_binary(float, expand_compact(options))
248261
end
249262

263+
defp calculate_precision(num, variance, precision) do
264+
num + (variance / :math.pow(10, precision))
265+
end
266+
250267
defp expand_compact([{:compact, false}|t]), do: expand_compact(t)
251268
defp expand_compact([{:compact, true}|t]), do: [:compact|expand_compact(t)]
252269
defp expand_compact([h|t]), do: [h|expand_compact(t)]

lib/elixir/test/elixir/float_test.exs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,41 @@ defmodule FloatTest do
2828
end
2929

3030
test :floor do
31-
assert Float.floor(12) === 12
32-
assert Float.floor(-12) === -12
33-
assert Float.floor(12.524235) === 12
34-
assert Float.floor(-12.5) === -13
35-
assert Float.floor(-12.524235) === -13
36-
assert Float.floor(7.5e3) === 7500
37-
assert Float.floor(7.5432e3) === 7543
38-
assert Float.floor(7.5e-3) === 0
39-
assert Float.floor(-12.32453e4) === -123246
40-
assert Float.floor(-12.32453e-10) === -1
41-
assert Float.floor(0.32453e-10) === 0
42-
assert Float.floor(-0.32453e-10) === -1
43-
assert Float.floor(1.32453e-10) === 0
31+
assert Float.floor(12.524235) === 12.0
32+
assert Float.floor(-12.5) === -13.0
33+
assert Float.floor(-12.524235) === -13.0
34+
assert Float.floor(7.5e3) === 7500.0
35+
assert Float.floor(7.5432e3) === 7543.0
36+
assert Float.floor(7.5e-3) === 0.0
37+
assert Float.floor(-12.32453e4) === -123246.0
38+
assert Float.floor(-12.32453e-10) === -1.0
39+
assert Float.floor(0.32453e-10) === 0.0
40+
assert Float.floor(-0.32453e-10) === -1.0
41+
assert Float.floor(1.32453e-10) === 0.0
42+
end
43+
44+
test :floor_with_precision do
45+
assert Float.floor(12.524235, 2) === 12.52
46+
assert Float.floor(-12.524235, 3) === -12.525
4447
end
4548

4649
test :ceil do
47-
assert Float.ceil(12) === 12
48-
assert Float.ceil(-12) === -12
49-
assert Float.ceil(12.524235) === 13
50-
assert Float.ceil(-12.5) === -12
51-
assert Float.ceil(-12.524235) === -12
52-
assert Float.ceil(7.5e3) === 7500
53-
assert Float.ceil(7.5432e3) === 7544
54-
assert Float.ceil(7.5e-3) === 1
55-
assert Float.ceil(-12.32453e4) === -123245
56-
assert Float.ceil(-12.32453e-10) === 0
57-
assert Float.ceil(0.32453e-10) === 1
58-
assert Float.ceil(-0.32453e-10) === 0
59-
assert Float.ceil(1.32453e-10) === 1
50+
assert Float.ceil(12.524235) === 13.0
51+
assert Float.ceil(-12.5) === -12.0
52+
assert Float.ceil(-12.524235) === -12.0
53+
assert Float.ceil(7.5e3) === 7500.0
54+
assert Float.ceil(7.5432e3) === 7544.0
55+
assert Float.ceil(7.5e-3) === 1.0
56+
assert Float.ceil(-12.32453e4) === -123245.0
57+
assert Float.ceil(-12.32453e-10) === 0.0
58+
assert Float.ceil(0.32453e-10) === 1.0
59+
assert Float.ceil(-0.32453e-10) === 0.0
60+
assert Float.ceil(1.32453e-10) === 1.0
61+
end
62+
63+
test :ceil_with_precision do
64+
assert Float.ceil(12.524235, 2) === 12.53
65+
assert Float.ceil(-12.524235, 3) === -12.524
6066
end
6167

6268
test :round do

0 commit comments

Comments
 (0)