Fix RDF.Decimal
- the canonical representation of given Decimals was not always correct, we now store always the canonical decimal as the Literal.value
This commit is contained in:
parent
2313e001fd
commit
ca3c4a0104
2 changed files with 71 additions and 75 deletions
|
@ -7,19 +7,17 @@ defmodule RDF.Decimal do
|
|||
alias Elixir.Decimal, as: D
|
||||
|
||||
|
||||
def build_literal_by_value(value, opts) when is_integer(value),
|
||||
do: value |> D.new() |> build_literal(to_string(value), opts)
|
||||
|
||||
def build_literal_by_value(value, opts),
|
||||
do: super(value, opts)
|
||||
|
||||
|
||||
def convert(%D{coef: coef} = value, opts) when coef in ~w[qNaN sNaN inf]a,
|
||||
do: super(value, opts)
|
||||
|
||||
def convert(%D{} = decimal, _), do: decimal
|
||||
def convert(%D{} = decimal, _),
|
||||
do: canonical_decimal(decimal)
|
||||
|
||||
def convert(value, _) when is_float(value), do: D.from_float(value)
|
||||
def convert(value, opts) when is_integer(value),
|
||||
do: value |> D.new() |> convert(opts)
|
||||
|
||||
def convert(value, opts) when is_float(value),
|
||||
do: value |> D.from_float() |> convert(opts)
|
||||
|
||||
def convert(value, opts) when is_binary(value) do
|
||||
if String.contains?(value, ~w[e E]) do
|
||||
|
@ -35,36 +33,34 @@ defmodule RDF.Decimal do
|
|||
def convert(value, opts), do: super(value, opts)
|
||||
|
||||
|
||||
def canonical_lexical(%D{sign: sign, coef: :qNaN}) do
|
||||
if sign == 1, do: "NaN", else: "-NaN"
|
||||
end
|
||||
def canonical_lexical(%D{sign: sign, coef: :qNaN}),
|
||||
do: if sign == 1, do: "NaN", else: "-NaN"
|
||||
|
||||
def canonical_lexical(%D{sign: sign, coef: :sNaN}) do
|
||||
if sign == 1, do: "sNaN", else: "-sNaN"
|
||||
end
|
||||
def canonical_lexical(%D{sign: sign, coef: :sNaN}),
|
||||
do: if sign == 1, do: "sNaN", else: "-sNaN"
|
||||
|
||||
def canonical_lexical(%D{sign: sign, coef: :inf}) do
|
||||
if sign == 1, do: "Infinity", else: "-Infinity"
|
||||
end
|
||||
def canonical_lexical(%D{sign: sign, coef: :inf}),
|
||||
do: if sign == 1, do: "Infinity", else: "-Infinity"
|
||||
|
||||
def canonical_lexical(%D{} = decimal) do
|
||||
decimal |> canonical_decimal() |> D.to_string(:normal)
|
||||
end
|
||||
def canonical_lexical(%D{} = decimal),
|
||||
do: D.to_string(decimal, :normal)
|
||||
|
||||
defp canonical_decimal(%D{coef: 0} = decimal), do: %{decimal | exp: -1}
|
||||
|
||||
defp canonical_decimal(%D{coef: coef, exp: 0} = decimal),
|
||||
def canonical_decimal(%D{coef: 0} = decimal),
|
||||
do: %{decimal | exp: -1}
|
||||
|
||||
def canonical_decimal(%D{coef: coef, exp: 0} = decimal),
|
||||
do: %{decimal | coef: coef * 10, exp: -1}
|
||||
|
||||
defp canonical_decimal(%D{coef: coef, exp: exp} = decimal)
|
||||
def canonical_decimal(%D{coef: coef, exp: exp} = decimal)
|
||||
when exp > 0,
|
||||
do: canonical_decimal(%{decimal | coef: coef * 10, exp: exp - 1})
|
||||
|
||||
defp canonical_decimal(%D{coef: coef} = decimal)
|
||||
def canonical_decimal(%D{coef: coef} = decimal)
|
||||
when Kernel.rem(coef, 10) != 0,
|
||||
do: decimal
|
||||
|
||||
defp canonical_decimal(%D{coef: coef, exp: exp} = decimal),
|
||||
def canonical_decimal(%D{coef: coef, exp: exp} = decimal),
|
||||
do: canonical_decimal(%{decimal | coef: Kernel.div(coef, 10), exp: exp + 1})
|
||||
|
||||
|
||||
|
|
|
@ -3,34 +3,36 @@ defmodule RDF.DecimalTest do
|
|||
# alias Elixir.Decimal, as: D
|
||||
use RDF.Datatype.Test.Case, datatype: RDF.Decimal, id: RDF.NS.XSD.decimal,
|
||||
valid: %{
|
||||
# input => { value lexical canonicaized }
|
||||
0 => {Elixir.Decimal.new(0), "0", "0.0"},
|
||||
1 => {Elixir.Decimal.new(1), "1", "1.0"},
|
||||
-1 => {Elixir.Decimal.new(-1), "-1", "-1.0"},
|
||||
1.0 => {Elixir.Decimal.new(1.0), nil, "1.0"},
|
||||
-3.14 => {Elixir.Decimal.new(-3.14), nil, "-3.14"},
|
||||
0.0E2 => {Elixir.Decimal.new(0.0E2), nil, "0.0"},
|
||||
1.2E3 => {Elixir.Decimal.new(1.2E3), nil, "1200.0"},
|
||||
Elixir.Decimal.new(1.0) => {Elixir.Decimal.new(1.0), nil, "1.0"},
|
||||
"1" => {Elixir.Decimal.new(1), "1", "1.0" },
|
||||
"01" => {Elixir.Decimal.new(1), "01", "1.0" },
|
||||
"0123" => {Elixir.Decimal.new(123), "0123", "123.0" },
|
||||
"-1" => {Elixir.Decimal.new(-1), "-1", "-1.0" },
|
||||
"1." => {Elixir.Decimal.new(1), "1.", "1.0" },
|
||||
"1.0" => {Elixir.Decimal.new(1.0), nil, "1.0" },
|
||||
"1.000000000" => {Elixir.Decimal.new("1.000000000"), "1.000000000", "1.0" },
|
||||
"+001.00" => {Elixir.Decimal.new("1.00"), "+001.00", "1.0" },
|
||||
"123.456" => {Elixir.Decimal.new(123.456), nil, "123.456" },
|
||||
"0123.456" => {Elixir.Decimal.new(123.456), "0123.456", "123.456" },
|
||||
"010.020" => {Elixir.Decimal.new("10.020"), "010.020", "10.02" },
|
||||
"2.3" => {Elixir.Decimal.new(2.3), nil, "2.3" },
|
||||
"2.345" => {Elixir.Decimal.new(2.345), nil, "2.345" },
|
||||
"2.234000005" => {Elixir.Decimal.new(2.234000005), nil, "2.234000005" },
|
||||
# input => {value lexical canonicalized}
|
||||
0 => {Elixir.Decimal.new(0.0), nil, "0.0"},
|
||||
1 => {Elixir.Decimal.new(1.0), nil, "1.0"},
|
||||
-1 => {Elixir.Decimal.new(-1.0), nil, "-1.0"},
|
||||
1.0 => {Elixir.Decimal.new(1.0), nil, "1.0"},
|
||||
-3.14 => {Elixir.Decimal.new(-3.14), nil, "-3.14"},
|
||||
0.0E2 => {Elixir.Decimal.new(0.0), nil, "0.0"},
|
||||
1.2E3 => {Elixir.Decimal.new("1200.0"), nil, "1200.0"},
|
||||
Elixir.Decimal.new(1.0) => {Elixir.Decimal.new(1.0), nil, "1.0"},
|
||||
Elixir.Decimal.new(1) => {Elixir.Decimal.new(1.0), nil, "1.0"},
|
||||
Elixir.Decimal.new(1.2E3) => {Elixir.Decimal.new("1200.0"), nil, "1200.0"},
|
||||
"1" => {Elixir.Decimal.new(1.0), "1", "1.0" },
|
||||
"01" => {Elixir.Decimal.new(1.0), "01", "1.0" },
|
||||
"0123" => {Elixir.Decimal.new(123.0), "0123", "123.0" },
|
||||
"-1" => {Elixir.Decimal.new(-1.0), "-1", "-1.0" },
|
||||
"1." => {Elixir.Decimal.new(1.0), "1.", "1.0" },
|
||||
"1.0" => {Elixir.Decimal.new(1.0), nil, "1.0" },
|
||||
"1.000000000" => {Elixir.Decimal.new(1.0), "1.000000000", "1.0" },
|
||||
"+001.00" => {Elixir.Decimal.new(1.0), "+001.00", "1.0" },
|
||||
"123.456" => {Elixir.Decimal.new(123.456), nil, "123.456" },
|
||||
"0123.456" => {Elixir.Decimal.new(123.456), "0123.456", "123.456" },
|
||||
"010.020" => {Elixir.Decimal.new(10.02), "010.020", "10.02" },
|
||||
"2.3" => {Elixir.Decimal.new(2.3), nil, "2.3" },
|
||||
"2.345" => {Elixir.Decimal.new(2.345), nil, "2.345" },
|
||||
"2.234000005" => {Elixir.Decimal.new(2.234000005), nil, "2.234000005" },
|
||||
"1.234567890123456789012345789"
|
||||
=> {Elixir.Decimal.new("1.234567890123456789012345789"),
|
||||
=> {Elixir.Decimal.new("1.234567890123456789012345789"),
|
||||
nil, "1.234567890123456789012345789" },
|
||||
".3" => {Elixir.Decimal.new(0.3), ".3", "0.3" },
|
||||
"-.3" => {Elixir.Decimal.new(-0.3), "-.3", "-0.3" },
|
||||
".3" => {Elixir.Decimal.new(0.3), ".3", "0.3" },
|
||||
"-.3" => {Elixir.Decimal.new(-0.3), "-.3", "-0.3" },
|
||||
},
|
||||
invalid: ~w(foo 10.1e1 12.xyz 3,5 NaN Inf) ++ [true, false, "1.0 foo", "foo 1.0",
|
||||
Elixir.Decimal.new("NaN"), Elixir.Decimal.new("Inf")]
|
||||
|
@ -69,29 +71,27 @@ defmodule RDF.DecimalTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "Decimal.canonical_lexical/1" do
|
||||
assert Decimal.canonical_lexical(~d"0") == "0.0"
|
||||
assert Decimal.canonical_lexical(~d"0.0") == "0.0"
|
||||
assert Decimal.canonical_lexical(~d"0.001") == "0.001"
|
||||
assert Decimal.canonical_lexical(~d"-0") == "-0.0"
|
||||
assert Decimal.canonical_lexical(~d"-1") == "-1.0"
|
||||
assert Decimal.canonical_lexical(~d"-0.00") == "-0.0"
|
||||
assert Decimal.canonical_lexical(~d"1.00") == "1.0"
|
||||
assert Decimal.canonical_lexical(~d"1000") == "1000.0"
|
||||
assert Decimal.canonical_lexical(~d"1000.000000") == "1000.0"
|
||||
assert Decimal.canonical_lexical(~d"12345.000") == "12345.0"
|
||||
assert Decimal.canonical_lexical(~d"42") == "42.0"
|
||||
assert Decimal.canonical_lexical(~d"42.42") == "42.42"
|
||||
assert Decimal.canonical_lexical(~d"0.42") == "0.42"
|
||||
assert Decimal.canonical_lexical(~d"0.0042") == "0.0042"
|
||||
assert Decimal.canonical_lexical(~d"010.020") == "10.02"
|
||||
assert Decimal.canonical_lexical(~d"-1.23") == "-1.23"
|
||||
assert Decimal.canonical_lexical(~d"-0.0123") == "-0.0123"
|
||||
assert Decimal.canonical_lexical(~d"1E+2") == "100.0"
|
||||
assert Decimal.canonical_lexical(~d"-42E+3") == "-42000.0"
|
||||
assert Decimal.canonical_lexical(~d"nan") == "NaN"
|
||||
assert Decimal.canonical_lexical(~d"-nan") == "-NaN"
|
||||
assert Decimal.canonical_lexical(~d"-inf") == "-Infinity"
|
||||
test "Decimal.canonical_decimal/1" do
|
||||
assert Decimal.canonical_decimal(~d"0") == ~d"0.0"
|
||||
assert Decimal.canonical_decimal(~d"0.0") == ~d"0.0"
|
||||
assert Decimal.canonical_decimal(~d"0.001") == ~d"0.001"
|
||||
assert Decimal.canonical_decimal(~d"-0") == ~d"-0.0"
|
||||
assert Decimal.canonical_decimal(~d"-1") == ~d"-1.0"
|
||||
assert Decimal.canonical_decimal(~d"-0.00") == ~d"-0.0"
|
||||
assert Decimal.canonical_decimal(~d"1.00") == ~d"1.0"
|
||||
assert Decimal.canonical_decimal(~d"1000") == ~d"1000.0"
|
||||
assert Decimal.canonical_decimal(~d"1000.000000") == ~d"1000.0"
|
||||
assert Decimal.canonical_decimal(~d"12345.000") == ~d"12345.0"
|
||||
assert Decimal.canonical_decimal(~d"42") == ~d"42.0"
|
||||
assert Decimal.canonical_decimal(~d"42.42") == ~d"42.42"
|
||||
assert Decimal.canonical_decimal(~d"0.42") == ~d"0.42"
|
||||
assert Decimal.canonical_decimal(~d"0.0042") == ~d"0.0042"
|
||||
assert Decimal.canonical_decimal(~d"010.020") == ~d"10.02"
|
||||
assert Decimal.canonical_decimal(~d"-1.23") == ~d"-1.23"
|
||||
assert Decimal.canonical_decimal(~d"-0.0123") == ~d"-0.0123"
|
||||
assert Decimal.canonical_decimal(~d"1E+2") == ~d"100.0"
|
||||
assert Decimal.canonical_decimal(~d"1.2E3") == ~d"1200.0"
|
||||
assert Decimal.canonical_decimal(~d"-42E+3") == ~d"-42000.0"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue