Add RDF.Numeric.ceil/1 and RDF.Numeric.floor/1
This commit is contained in:
parent
cb9585d87a
commit
974b2c8360
2 changed files with 128 additions and 0 deletions
|
@ -319,6 +319,80 @@ defmodule RDF.Numeric do
|
|||
defp xpath_round(decimal, precision),
|
||||
do: D.round(decimal, precision)
|
||||
|
||||
@doc """
|
||||
Rounds a numeric literal upwards to a whole number literal.
|
||||
|
||||
If the argument is not a valid numeric literal `nil` is returned.
|
||||
|
||||
see <http://www.w3.org/TR/xpath-functions/#func-ceil>
|
||||
|
||||
"""
|
||||
def ceil(literal)
|
||||
|
||||
def ceil(%Literal{datatype: @xsd_decimal} = literal) do
|
||||
if RDF.Decimal.valid?(literal) do
|
||||
literal.value
|
||||
|> D.round(0, (if literal.value.sign == -1, do: :down, else: :up))
|
||||
|> D.to_integer()
|
||||
|> RDF.Integer.new()
|
||||
end
|
||||
end
|
||||
|
||||
def ceil(%Literal{datatype: @xsd_double, value: value} = literal)
|
||||
when value in ~w[nan positive_infinity negative_infinity]a, do: literal
|
||||
|
||||
def ceil(%Literal{datatype: @xsd_double} = literal) do
|
||||
if RDF.Double.valid?(literal) do
|
||||
literal.value
|
||||
|> Float.ceil()
|
||||
|> trunc()
|
||||
|> RDF.Integer.new()
|
||||
end
|
||||
end
|
||||
|
||||
def ceil(%Literal{datatype: datatype} = literal) do
|
||||
if type?(datatype) and Literal.valid?(literal) do
|
||||
literal
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Rounds a numeric literal downwards to a whole number literal.
|
||||
|
||||
If the argument is not a valid numeric literal `nil` is returned.
|
||||
|
||||
see <http://www.w3.org/TR/xpath-functions/#func-floor>
|
||||
|
||||
"""
|
||||
def floor(literal)
|
||||
|
||||
def floor(%Literal{datatype: @xsd_decimal} = literal) do
|
||||
if RDF.Decimal.valid?(literal) do
|
||||
literal.value
|
||||
|> D.round(0, (if literal.value.sign == -1, do: :up, else: :down))
|
||||
|> D.to_integer()
|
||||
|> RDF.Integer.new()
|
||||
end
|
||||
end
|
||||
|
||||
def floor(%Literal{datatype: @xsd_double, value: value} = literal)
|
||||
when value in ~w[nan positive_infinity negative_infinity]a, do: literal
|
||||
|
||||
def floor(%Literal{datatype: @xsd_double} = literal) do
|
||||
if RDF.Double.valid?(literal) do
|
||||
literal.value
|
||||
|> Float.floor()
|
||||
|> trunc()
|
||||
|> RDF.Integer.new()
|
||||
end
|
||||
end
|
||||
|
||||
def floor(%Literal{datatype: datatype} = literal) do
|
||||
if type?(datatype) and Literal.valid?(literal) do
|
||||
literal
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
defp arithmetic_operation(op, arg1, arg2, fun) do
|
||||
if literal?(arg1) && literal?(arg2) do
|
||||
|
|
|
@ -409,4 +409,58 @@ defmodule RDF.NumericTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "ceil/1" do
|
||||
test "with xsd:integer" do
|
||||
assert RDF.integer(42) |> Numeric.ceil() == RDF.integer(42)
|
||||
assert RDF.integer(-42) |> Numeric.ceil() == RDF.integer(-42)
|
||||
end
|
||||
|
||||
test "with xsd:double" do
|
||||
assert RDF.double(10.5) |> Numeric.ceil() == RDF.integer(11)
|
||||
assert RDF.double(-10.5) |> Numeric.ceil() == RDF.integer(-10)
|
||||
|
||||
assert RDF.double("INF") |> Numeric.ceil() == RDF.double("INF")
|
||||
assert RDF.double("-INF") |> Numeric.ceil() == RDF.double("-INF")
|
||||
assert RDF.double("NAN") |> Numeric.ceil() == RDF.double("NAN")
|
||||
end
|
||||
|
||||
test "with xsd:decimal" do
|
||||
assert RDF.decimal(10.5) |> Numeric.ceil() == RDF.integer(11)
|
||||
assert RDF.decimal(-10.5) |> Numeric.ceil() == RDF.integer(-10)
|
||||
end
|
||||
|
||||
test "with invalid numeric literals" do
|
||||
assert RDF.integer("-3.14") |> Numeric.ceil() == nil
|
||||
assert RDF.double("foo") |> Numeric.ceil() == nil
|
||||
assert RDF.decimal("foo") |> Numeric.ceil() == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "floor/1" do
|
||||
test "with xsd:integer" do
|
||||
assert RDF.integer(42) |> Numeric.floor() == RDF.integer(42)
|
||||
assert RDF.integer(-42) |> Numeric.floor() == RDF.integer(-42)
|
||||
end
|
||||
|
||||
test "with xsd:double" do
|
||||
assert RDF.double(10.5) |> Numeric.floor() == RDF.integer(10)
|
||||
assert RDF.double(-10.5) |> Numeric.floor() == RDF.integer(-11)
|
||||
|
||||
assert RDF.double("INF") |> Numeric.floor() == RDF.double("INF")
|
||||
assert RDF.double("-INF") |> Numeric.floor() == RDF.double("-INF")
|
||||
assert RDF.double("NAN") |> Numeric.floor() == RDF.double("NAN")
|
||||
end
|
||||
|
||||
test "with xsd:decimal" do
|
||||
assert RDF.decimal(10.5) |> Numeric.floor() == RDF.integer(10)
|
||||
assert RDF.decimal(-10.5) |> Numeric.floor() == RDF.integer(-11)
|
||||
end
|
||||
|
||||
test "with invalid numeric literals" do
|
||||
assert RDF.integer("-3.14") |> Numeric.floor() == nil
|
||||
assert RDF.double("foo") |> Numeric.floor() == nil
|
||||
assert RDF.decimal("foo") |> Numeric.floor() == nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue