Add arithmetic operations on RDF.Numeric
This commit is contained in:
parent
ca3c4a0104
commit
7ad3c0acc1
3 changed files with 519 additions and 7 deletions
|
@ -15,7 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
|||
- `RDF.Decimal` datatype for `xsd:decimal` literals and support for decimal
|
||||
literals in Turtle encoder
|
||||
- `RDF.Numeric` with a list of all numeric datatypes and shared functions for
|
||||
all numeric literals
|
||||
all numeric literals, eg. arithmetic functions
|
||||
- the logical operators and the Effective Boolean Value (EBV) coercion algorithm
|
||||
from the XPath and SPARQL specs on `RDF.Boolean`
|
||||
- `RDF.Term.equal?/2` and `RDF.Term.equal_value?/2`
|
||||
|
|
|
@ -27,6 +27,10 @@ defmodule RDF.Numeric do
|
|||
XSD.positiveInteger,
|
||||
]
|
||||
|
||||
@xsd_decimal XSD.decimal
|
||||
@xsd_double XSD.double
|
||||
|
||||
|
||||
@doc """
|
||||
The list of all numeric datatypes.
|
||||
"""
|
||||
|
@ -37,7 +41,12 @@ defmodule RDF.Numeric do
|
|||
"""
|
||||
def type?(type), do: MapSet.member?(@types, type)
|
||||
|
||||
@xsd_decimal XSD.decimal
|
||||
@doc """
|
||||
Returns if a given literal has a numeric datatype.
|
||||
"""
|
||||
def literal?(%Literal{datatype: datatype}), do: type?(datatype)
|
||||
def literal?(_), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
Tests for numeric value equality of two numeric literals.
|
||||
|
@ -60,11 +69,6 @@ defmodule RDF.Numeric do
|
|||
%Literal{datatype: right_datatype, value: right})
|
||||
do
|
||||
if type?(left_datatype) and type?(right_datatype) do
|
||||
# We rely here on Elixirs numeric equality comparison.
|
||||
# TODO: There are probably problematic edge-case, which might require an
|
||||
# TODO: implementation of XPath type promotion and subtype substitution
|
||||
# - https://www.w3.org/TR/xpath-functions/#op.numeric
|
||||
# - https://www.w3.org/TR/xpath20/#id-type-promotion-and-operator-mapping
|
||||
left == right
|
||||
end
|
||||
end
|
||||
|
@ -76,4 +80,198 @@ defmodule RDF.Numeric do
|
|||
defp equal_decimal_value?(left, %D{} = right), do: equal_decimal_value?(D.new(left), right)
|
||||
defp equal_decimal_value?(_, _), do: nil
|
||||
|
||||
|
||||
def zero?(%Literal{value: value}), do: zero_value?(value)
|
||||
|
||||
defp zero_value?(zero) when zero == 0, do: true
|
||||
defp zero_value?(%D{coef: 0}), do: true
|
||||
defp zero_value?(_), do: false
|
||||
|
||||
|
||||
def negative_zero?(%Literal{value: zero, uncanonical_lexical: "-" <> _, datatype: @xsd_double})
|
||||
when zero == 0, do: true
|
||||
|
||||
def negative_zero?(%Literal{value: %D{sign: -1, coef: 0}}), do: true
|
||||
|
||||
def negative_zero?(_), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
Adds two numeric literals.
|
||||
|
||||
For `xsd:float` or `xsd:double` values, if one of the operands is a zero or a
|
||||
finite number and the other is INF or -INF, INF or -INF is returned. If both
|
||||
operands are INF, INF is returned. If both operands are -INF, -INF is returned.
|
||||
If one of the operands is INF and the other is -INF, NaN is returned.
|
||||
|
||||
If one of the given arguments is not a numeric literal, `nil` is returned.
|
||||
|
||||
see <http://www.w3.org/TR/xpath-functions/#func-numeric-add>
|
||||
|
||||
"""
|
||||
def add(arg1, arg2) do
|
||||
arithmetic_operation :+, arg1, arg2, fn
|
||||
:positive_infinity, :negative_infinity, _ -> :nan
|
||||
:negative_infinity, :positive_infinity, _ -> :nan
|
||||
:positive_infinity, _, _ -> :positive_infinity
|
||||
_, :positive_infinity, _ -> :positive_infinity
|
||||
:negative_infinity, _, _ -> :negative_infinity
|
||||
_, :negative_infinity, _ -> :negative_infinity
|
||||
%D{} = arg1, %D{} = arg2, _ -> D.add(arg1, arg2)
|
||||
arg1, arg2, _ -> arg1 + arg2
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Subtracts two numeric literals.
|
||||
|
||||
For `xsd:float` or `xsd:double` values, if one of the operands is a zero or a
|
||||
finite number and the other is INF or -INF, an infinity of the appropriate sign
|
||||
is returned. If both operands are INF or -INF, NaN is returned. If one of the
|
||||
operands is INF and the other is -INF, an infinity of the appropriate sign is
|
||||
returned.
|
||||
|
||||
If one of the given arguments is not a numeric literal, `nil` is returned.
|
||||
|
||||
see <http://www.w3.org/TR/xpath-functions/#func-numeric-subtract>
|
||||
|
||||
"""
|
||||
def subtract(arg1, arg2) do
|
||||
arithmetic_operation :-, arg1, arg2, fn
|
||||
:positive_infinity, :positive_infinity, _ -> :nan
|
||||
:negative_infinity, :negative_infinity, _ -> :nan
|
||||
:positive_infinity, :negative_infinity, _ -> :positive_infinity
|
||||
:negative_infinity, :positive_infinity, _ -> :negative_infinity
|
||||
:positive_infinity, _, _ -> :positive_infinity
|
||||
_, :positive_infinity, _ -> :negative_infinity
|
||||
:negative_infinity, _, _ -> :negative_infinity
|
||||
_, :negative_infinity, _ -> :positive_infinity
|
||||
%D{} = arg1, %D{} = arg2, _ -> D.sub(arg1, arg2)
|
||||
arg1, arg2, _ -> arg1 - arg2
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Multiplies two numeric literals.
|
||||
|
||||
For `xsd:float` or `xsd:double` values, if one of the operands is a zero and
|
||||
the other is an infinity, NaN is returned. If one of the operands is a non-zero
|
||||
number and the other is an infinity, an infinity with the appropriate sign is
|
||||
returned.
|
||||
|
||||
If one of the given arguments is not a numeric literal, `nil` is returned.
|
||||
|
||||
see <http://www.w3.org/TR/xpath-functions/#func-numeric-multiply>
|
||||
|
||||
"""
|
||||
def multiply(arg1, arg2) do
|
||||
arithmetic_operation :*, arg1, arg2, fn
|
||||
:positive_infinity, :negative_infinity, _ -> :nan
|
||||
:negative_infinity, :positive_infinity, _ -> :nan
|
||||
inf, zero, _ when inf in [:positive_infinity, :negative_infinity] and zero == 0 -> :nan
|
||||
zero, inf, _ when inf in [:positive_infinity, :negative_infinity] and zero == 0 -> :nan
|
||||
:positive_infinity, number, _ when number < 0 -> :negative_infinity
|
||||
number, :positive_infinity, _ when number < 0 -> :negative_infinity
|
||||
:positive_infinity, _, _ -> :positive_infinity
|
||||
_, :positive_infinity, _ -> :positive_infinity
|
||||
:negative_infinity, number, _ when number < 0 -> :positive_infinity
|
||||
number, :negative_infinity, _ when number < 0 -> :positive_infinity
|
||||
:negative_infinity, _, _ -> :negative_infinity
|
||||
_, :negative_infinity, _ -> :negative_infinity
|
||||
%D{} = arg1, %D{} = arg2, _ -> D.mult(arg1, arg2)
|
||||
arg1, arg2, _ -> arg1 * arg2
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Divides two numeric literals.
|
||||
|
||||
For `xsd:float` and `xsd:double` operands, floating point division is performed
|
||||
as specified in [IEEE 754-2008]. A positive number divided by positive zero
|
||||
returns INF. A negative number divided by positive zero returns -INF. Division
|
||||
by negative zero returns -INF and INF, respectively. Positive or negative zero
|
||||
divided by positive or negative zero returns NaN. Also, INF or -INF divided by
|
||||
INF or -INF returns NaN.
|
||||
|
||||
If one of the given arguments is not a numeric literal, `nil` is returned.
|
||||
|
||||
'nil` is also returned for `xsd:decimal` and `xsd:integer` operands, if the
|
||||
divisor is (positive or negative) zero.
|
||||
|
||||
see <http://www.w3.org/TR/xpath-functions/#func-numeric-divide>
|
||||
|
||||
"""
|
||||
def divide(arg1, arg2) do
|
||||
negative_zero = negative_zero?(arg2)
|
||||
arithmetic_operation :/, arg1, arg2, fn
|
||||
inf1, inf2, _ when inf1 in [:positive_infinity, :negative_infinity] and
|
||||
inf2 in [:positive_infinity, :negative_infinity] ->
|
||||
:nan
|
||||
%D{} = arg1, %D{coef: coef} = arg2, _ ->
|
||||
unless coef == 0, do: D.div(arg1, arg2)
|
||||
arg1, arg2, result_type ->
|
||||
if zero_value?(arg2) do
|
||||
cond do
|
||||
not result_type in [XSD.double] -> nil # TODO: or XSD.float
|
||||
zero_value?(arg1) -> :nan
|
||||
negative_zero and arg1 < 0 -> :positive_infinity
|
||||
negative_zero -> :negative_infinity
|
||||
arg1 < 0 -> :negative_infinity
|
||||
true -> :positive_infinity
|
||||
end
|
||||
else
|
||||
arg1 / arg2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
defp arithmetic_operation(op, arg1, arg2, fun) do
|
||||
if literal?(arg1) && literal?(arg2) do
|
||||
with result_type = result_type(op, arg1.datatype, arg2.datatype),
|
||||
{arg1, arg2} = type_conversion(arg1, arg2, result_type),
|
||||
result = fun.(arg1.value, arg2.value, result_type)
|
||||
do
|
||||
unless is_nil(result),
|
||||
do: Literal.new(result, datatype: result_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
defp type_conversion(%Literal{datatype: @xsd_decimal} = arg1,
|
||||
%Literal{value: arg2}, @xsd_decimal),
|
||||
do: {arg1, RDF.decimal(arg2)}
|
||||
|
||||
defp type_conversion(%Literal{value: arg1},
|
||||
%Literal{datatype: @xsd_decimal} = arg2, @xsd_decimal),
|
||||
do: {RDF.decimal(arg1), arg2}
|
||||
|
||||
defp type_conversion(%Literal{datatype: @xsd_decimal, value: arg1}, arg2, @xsd_double),
|
||||
do: {arg1 |> D.to_float() |> RDF.double(), arg2}
|
||||
|
||||
defp type_conversion(arg1, %Literal{datatype: @xsd_decimal, value: arg2}, @xsd_double),
|
||||
do: {arg1, arg2 |> D.to_float() |> RDF.double()}
|
||||
|
||||
defp type_conversion(arg1, arg2, _), do: {arg1, arg2}
|
||||
|
||||
|
||||
defp result_type(:/, type1, type2) do
|
||||
types = [type1, type2]
|
||||
cond do
|
||||
XSD.double in types -> XSD.double
|
||||
XSD.float in types -> XSD.float
|
||||
true -> XSD.decimal
|
||||
end
|
||||
end
|
||||
|
||||
defp result_type(_, type1, type2) do
|
||||
types = [type1, type2]
|
||||
cond do
|
||||
XSD.double in types -> XSD.double
|
||||
XSD.float in types -> XSD.float
|
||||
XSD.decimal in types -> XSD.decimal
|
||||
true -> XSD.integer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
314
test/unit/datatypes/numeric_test.exs
Normal file
314
test/unit/datatypes/numeric_test.exs
Normal file
|
@ -0,0 +1,314 @@
|
|||
defmodule RDF.NumericTest do
|
||||
use RDF.Test.Case
|
||||
|
||||
alias RDF.Numeric
|
||||
|
||||
|
||||
@positive_infinity RDF.double(:positive_infinity)
|
||||
@negative_infinity RDF.double(:negative_infinity)
|
||||
@nan RDF.double(:nan)
|
||||
|
||||
|
||||
@negative_zeros ~w[
|
||||
-0
|
||||
-000
|
||||
-0.0
|
||||
-0.00000
|
||||
]
|
||||
|
||||
test "negative_zero?/1" do
|
||||
Enum.each @negative_zeros, fn negative_zero ->
|
||||
assert Numeric.negative_zero?(RDF.double(negative_zero))
|
||||
assert Numeric.negative_zero?(RDF.decimal(negative_zero))
|
||||
end
|
||||
|
||||
refute Numeric.negative_zero?(RDF.double("-0.00001"))
|
||||
refute Numeric.negative_zero?(RDF.decimal("-0.00001"))
|
||||
end
|
||||
|
||||
test "zero?/1" do
|
||||
assert Numeric.zero?(RDF.integer(0))
|
||||
assert Numeric.zero?(RDF.integer("0"))
|
||||
|
||||
~w[
|
||||
0
|
||||
000
|
||||
0.0
|
||||
00.00
|
||||
]
|
||||
|> Enum.each(fn positive_zero ->
|
||||
assert Numeric.zero?(RDF.double(positive_zero))
|
||||
assert Numeric.zero?(RDF.decimal(positive_zero))
|
||||
end)
|
||||
|
||||
Enum.each @negative_zeros, fn negative_zero ->
|
||||
assert Numeric.zero?(RDF.double(negative_zero))
|
||||
assert Numeric.zero?(RDF.decimal(negative_zero))
|
||||
end
|
||||
|
||||
refute Numeric.zero?(RDF.double("-0.00001"))
|
||||
refute Numeric.zero?(RDF.decimal("-0.00001"))
|
||||
end
|
||||
|
||||
describe "add/2" do
|
||||
test "xsd:integer literal + xsd:integer literal" do
|
||||
assert Numeric.add(RDF.integer(1), RDF.integer(2)) == RDF.integer(3)
|
||||
end
|
||||
|
||||
test "xsd:decimal literal + xsd:integer literal" do
|
||||
assert Numeric.add(RDF.decimal(1.1), RDF.integer(2)) == RDF.decimal(3.1)
|
||||
end
|
||||
|
||||
test "xsd:double literal + xsd:integer literal" do
|
||||
result = Numeric.add(RDF.double(1.1), RDF.integer(2))
|
||||
expected = RDF.double(3.1)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:decimal literal + xsd:double literal" do
|
||||
result = Numeric.add(RDF.decimal(1.1), RDF.double(2.2))
|
||||
expected = RDF.double(3.3)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "if one of the operands is a zero or a finite number and the other is INF or -INF, INF or -INF is returned" do
|
||||
assert Numeric.add(@positive_infinity, RDF.double(0)) == @positive_infinity
|
||||
assert Numeric.add(@positive_infinity, RDF.double(3.14)) == @positive_infinity
|
||||
assert Numeric.add(RDF.double(0), @positive_infinity) == @positive_infinity
|
||||
assert Numeric.add(RDF.double(3.14), @positive_infinity) == @positive_infinity
|
||||
|
||||
assert Numeric.add(@negative_infinity, RDF.double(0)) == @negative_infinity
|
||||
assert Numeric.add(@negative_infinity, RDF.double(3.14)) == @negative_infinity
|
||||
assert Numeric.add(RDF.double(0), @negative_infinity) == @negative_infinity
|
||||
assert Numeric.add(RDF.double(3.14), @negative_infinity) == @negative_infinity
|
||||
end
|
||||
|
||||
test "if both operands are INF, INF is returned" do
|
||||
assert Numeric.add(@positive_infinity, @positive_infinity) == @positive_infinity
|
||||
end
|
||||
|
||||
test "if both operands are -INF, -INF is returned" do
|
||||
assert Numeric.add(@negative_infinity, @negative_infinity) == @negative_infinity
|
||||
end
|
||||
|
||||
test "if one of the operands is INF and the other is -INF, NaN is returned" do
|
||||
assert Numeric.add(@positive_infinity, @negative_infinity) == RDF.double(:nan)
|
||||
assert Numeric.add(@negative_infinity, @positive_infinity) == RDF.double(:nan)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "subtract/2" do
|
||||
test "xsd:integer literal - xsd:integer literal" do
|
||||
assert Numeric.subtract(RDF.integer(3), RDF.integer(2)) == RDF.integer(1)
|
||||
end
|
||||
|
||||
test "xsd:decimal literal - xsd:integer literal" do
|
||||
assert Numeric.subtract(RDF.decimal(3.3), RDF.integer(2)) == RDF.decimal(1.3)
|
||||
end
|
||||
|
||||
test "xsd:double literal - xsd:integer literal" do
|
||||
result = Numeric.subtract(RDF.double(3.3), RDF.integer(2))
|
||||
expected = RDF.double(1.3)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:decimal literal - xsd:double literal" do
|
||||
result = Numeric.subtract(RDF.decimal(3.3), RDF.double(2.2))
|
||||
expected = RDF.double(1.1)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "if one of the operands is a zero or a finite number and the other is INF or -INF, an infinity of the appropriate sign is returned" do
|
||||
assert Numeric.subtract(@positive_infinity, RDF.double(0)) == @positive_infinity
|
||||
assert Numeric.subtract(@positive_infinity, RDF.double(3.14)) == @positive_infinity
|
||||
assert Numeric.subtract(RDF.double(0), @positive_infinity) == @negative_infinity
|
||||
assert Numeric.subtract(RDF.double(3.14), @positive_infinity) == @negative_infinity
|
||||
|
||||
assert Numeric.subtract(@negative_infinity, RDF.double(0)) == @negative_infinity
|
||||
assert Numeric.subtract(@negative_infinity, RDF.double(3.14)) == @negative_infinity
|
||||
assert Numeric.subtract(RDF.double(0), @negative_infinity) == @positive_infinity
|
||||
assert Numeric.subtract(RDF.double(3.14), @negative_infinity) == @positive_infinity
|
||||
end
|
||||
|
||||
test "if both operands are INF or -INF, NaN is returned" do
|
||||
assert Numeric.subtract(@positive_infinity, @positive_infinity) == RDF.double(:nan)
|
||||
assert Numeric.subtract(@negative_infinity, @negative_infinity) == RDF.double(:nan)
|
||||
end
|
||||
|
||||
test "if one of the operands is INF and the other is -INF, an infinity of the appropriate sign is returned" do
|
||||
assert Numeric.subtract(@positive_infinity, @negative_infinity) == @positive_infinity
|
||||
assert Numeric.subtract(@negative_infinity, @positive_infinity) == @negative_infinity
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "multiply/2" do
|
||||
test "xsd:integer literal * xsd:integer literal" do
|
||||
assert Numeric.multiply(RDF.integer(2), RDF.integer(3)) == RDF.integer(6)
|
||||
end
|
||||
|
||||
test "xsd:decimal literal * xsd:integer literal" do
|
||||
assert Numeric.multiply(RDF.decimal(1.5), RDF.integer(3)) == RDF.decimal(4.5)
|
||||
end
|
||||
|
||||
test "xsd:double literal * xsd:integer literal" do
|
||||
result = Numeric.multiply(RDF.double(1.5), RDF.integer(3))
|
||||
expected = RDF.double(4.5)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:decimal literal * xsd:double literal" do
|
||||
result = Numeric.multiply(RDF.decimal(0.5), RDF.double(2.5))
|
||||
expected = RDF.double(1.25)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "if one of the operands is a zero and the other is an infinity, NaN is returned" do
|
||||
assert Numeric.multiply(@positive_infinity, RDF.double(0.0)) == @nan
|
||||
assert Numeric.multiply(RDF.integer(0), @positive_infinity) == @nan
|
||||
assert Numeric.multiply(RDF.decimal(0), @positive_infinity) == @nan
|
||||
|
||||
assert Numeric.multiply(@negative_infinity, RDF.double(0)) == @nan
|
||||
assert Numeric.multiply(RDF.integer(0), @negative_infinity) == @nan
|
||||
assert Numeric.multiply(RDF.decimal(0.0), @negative_infinity) == @nan
|
||||
end
|
||||
|
||||
test "if one of the operands is a non-zero number and the other is an infinity, an infinity with the appropriate sign is returned" do
|
||||
assert Numeric.multiply(@positive_infinity, RDF.double(3.14)) == @positive_infinity
|
||||
assert Numeric.multiply(RDF.double(3.14), @positive_infinity) == @positive_infinity
|
||||
assert Numeric.multiply(@positive_infinity, RDF.double(-3.14)) == @negative_infinity
|
||||
assert Numeric.multiply(RDF.double(-3.14), @positive_infinity) == @negative_infinity
|
||||
|
||||
assert Numeric.multiply(@negative_infinity, RDF.double(3.14)) == @negative_infinity
|
||||
assert Numeric.multiply(RDF.double(3.14), @negative_infinity) == @negative_infinity
|
||||
assert Numeric.multiply(@negative_infinity, RDF.double(-3.14)) == @positive_infinity
|
||||
assert Numeric.multiply(RDF.double(-3.14), @negative_infinity) == @positive_infinity
|
||||
end
|
||||
|
||||
# The following are assertions are not part of the spec.
|
||||
|
||||
test "if both operands are INF, INF is returned" do
|
||||
assert Numeric.multiply(@positive_infinity, @positive_infinity) == @positive_infinity
|
||||
end
|
||||
|
||||
test "if both operands are -INF, -INF is returned" do
|
||||
assert Numeric.multiply(@negative_infinity, @negative_infinity) == @negative_infinity
|
||||
end
|
||||
|
||||
test "if one of the operands is INF and the other is -INF, NaN is returned" do
|
||||
assert Numeric.multiply(@positive_infinity, @negative_infinity) == RDF.double(:nan)
|
||||
assert Numeric.multiply(@negative_infinity, @positive_infinity) == RDF.double(:nan)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "divide/2" do
|
||||
test "xsd:integer literal / xsd:integer literal" do
|
||||
assert Numeric.divide(RDF.integer(4), RDF.integer(2)) == RDF.decimal(2.0)
|
||||
end
|
||||
|
||||
test "xsd:decimal literal / xsd:integer literal" do
|
||||
assert Numeric.divide(RDF.decimal(4), RDF.integer(2)) == RDF.decimal(2.0)
|
||||
end
|
||||
|
||||
test "xsd:double literal / xsd:integer literal" do
|
||||
result = Numeric.divide(RDF.double(4), RDF.integer(2))
|
||||
expected = RDF.double(2)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:decimal literal / xsd:double literal" do
|
||||
result = Numeric.divide(RDF.decimal(4), RDF.double(2))
|
||||
expected = RDF.double(2)
|
||||
assert result.datatype == expected.datatype
|
||||
assert_in_delta result.value, expected.value, 0.000000000000001
|
||||
end
|
||||
|
||||
test "a positive number divided by positive zero returns INF" do
|
||||
assert Numeric.divide(RDF.double(1.0), RDF.double(0.0)) == @positive_infinity
|
||||
assert Numeric.divide(RDF.double(1.0), RDF.decimal(0.0)) == @positive_infinity
|
||||
assert Numeric.divide(RDF.double(1.0), RDF.integer(0)) == @positive_infinity
|
||||
assert Numeric.divide(RDF.decimal(1.0), RDF.double(0.0)) == @positive_infinity
|
||||
assert Numeric.divide(RDF.integer(1), RDF.double(0.0)) == @positive_infinity
|
||||
end
|
||||
|
||||
test "a negative number divided by positive zero returns -INF" do
|
||||
assert Numeric.divide(RDF.double(-1.0), RDF.double(0.0)) == @negative_infinity
|
||||
assert Numeric.divide(RDF.double(-1.0), RDF.decimal(0.0)) == @negative_infinity
|
||||
assert Numeric.divide(RDF.double(-1.0), RDF.integer(0)) == @negative_infinity
|
||||
assert Numeric.divide(RDF.decimal(-1.0), RDF.double(0.0)) == @negative_infinity
|
||||
assert Numeric.divide(RDF.integer(-1), RDF.double(0.0)) == @negative_infinity
|
||||
end
|
||||
|
||||
test "a positive number divided by negative zero returns -INF" do
|
||||
assert Numeric.divide(RDF.double(1.0), RDF.double("-0.0")) == @negative_infinity
|
||||
assert Numeric.divide(RDF.double(1.0), RDF.decimal("-0.0")) == @negative_infinity
|
||||
assert Numeric.divide(RDF.decimal(1.0), RDF.double("-0.0")) == @negative_infinity
|
||||
assert Numeric.divide(RDF.integer(1), RDF.double("-0.0")) == @negative_infinity
|
||||
end
|
||||
|
||||
test "a negative number divided by negative zero returns INF" do
|
||||
assert Numeric.divide(RDF.double(-1.0), RDF.double("-0.0")) == @positive_infinity
|
||||
assert Numeric.divide(RDF.double(-1.0), RDF.decimal("-0.0")) == @positive_infinity
|
||||
assert Numeric.divide(RDF.decimal(-1.0), RDF.double("-0.0")) == @positive_infinity
|
||||
assert Numeric.divide(RDF.integer(-1), RDF.double("-0.0")) == @positive_infinity
|
||||
end
|
||||
|
||||
test "nil is returned for xs:decimal and xs:integer operands, if the divisor is (positive or negative) zero" do
|
||||
assert Numeric.divide(RDF.decimal(1.0), RDF.decimal(0.0)) == nil
|
||||
assert Numeric.divide(RDF.decimal(1.0), RDF.integer(0)) == nil
|
||||
assert Numeric.divide(RDF.decimal(-1.0), RDF.decimal(0.0)) == nil
|
||||
assert Numeric.divide(RDF.decimal(-1.0), RDF.integer(0)) == nil
|
||||
assert Numeric.divide(RDF.integer(1), RDF.integer(0)) == nil
|
||||
assert Numeric.divide(RDF.integer(1), RDF.decimal(0.0)) == nil
|
||||
assert Numeric.divide(RDF.integer(-1), RDF.integer(0)) == nil
|
||||
assert Numeric.divide(RDF.integer(-1), RDF.decimal(0.0)) == nil
|
||||
end
|
||||
|
||||
test "positive or negative zero divided by positive or negative zero returns NaN" do
|
||||
assert Numeric.divide(RDF.double( "-0.0"), RDF.double(0.0)) == @nan
|
||||
assert Numeric.divide(RDF.double( "-0.0"), RDF.decimal(0.0)) == @nan
|
||||
assert Numeric.divide(RDF.double( "-0.0"), RDF.integer(0)) == @nan
|
||||
assert Numeric.divide(RDF.decimal("-0.0"), RDF.double(0.0)) == @nan
|
||||
assert Numeric.divide(RDF.integer("-0"), RDF.double(0.0)) == @nan
|
||||
|
||||
assert Numeric.divide(RDF.double( "0.0"), RDF.double(0.0)) == @nan
|
||||
assert Numeric.divide(RDF.double( "0.0"), RDF.decimal(0.0)) == @nan
|
||||
assert Numeric.divide(RDF.double( "0.0"), RDF.integer(0)) == @nan
|
||||
assert Numeric.divide(RDF.decimal("0.0"), RDF.double(0.0)) == @nan
|
||||
assert Numeric.divide(RDF.integer("0"), RDF.double(0.0)) == @nan
|
||||
|
||||
assert Numeric.divide(RDF.double(0.0) , RDF.double( "-0.0")) == @nan
|
||||
assert Numeric.divide(RDF.decimal(0.0), RDF.double( "-0.0")) == @nan
|
||||
assert Numeric.divide(RDF.integer(0) , RDF.double( "-0.0")) == @nan
|
||||
assert Numeric.divide(RDF.double(0.0) , RDF.decimal("-0.0")) == @nan
|
||||
assert Numeric.divide(RDF.double(0.0) , RDF.integer("-0")) == @nan
|
||||
|
||||
assert Numeric.divide(RDF.double(0.0) , RDF.double( "0.0")) == @nan
|
||||
assert Numeric.divide(RDF.decimal(0.0), RDF.double( "0.0")) == @nan
|
||||
assert Numeric.divide(RDF.integer(0) , RDF.double( "0.0")) == @nan
|
||||
assert Numeric.divide(RDF.double(0.0) , RDF.decimal("0.0")) == @nan
|
||||
assert Numeric.divide(RDF.double(0.0) , RDF.integer("0")) == @nan
|
||||
|
||||
end
|
||||
|
||||
test "INF or -INF divided by INF or -INF returns NaN" do
|
||||
assert Numeric.divide(@positive_infinity, @positive_infinity) == @nan
|
||||
assert Numeric.divide(@negative_infinity, @negative_infinity) == @nan
|
||||
assert Numeric.divide(@positive_infinity, @negative_infinity) == @nan
|
||||
assert Numeric.divide(@negative_infinity, @positive_infinity) == @nan
|
||||
end
|
||||
|
||||
# TODO: What happens when using INF/-INF on division with numbers?
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue