Feel.Value.Number (feel v0.1.0)

Copy Markdown View Source

The FEEL type number (DMN 1.6, section 10.3.2.3.1).

A number is a decimal with at most 34 significant digits, as in the IEEE 754 decimal128 format, and it is exact: 0.1 + 0.2 is 0.3. It is represented as a Decimal. FEEL has no "not a number" and no infinities, so a Decimal with either of those values is not a FEEL number; a result that would be one is null instead.

value?/1 checks only that a term is a finite decimal. Keeping results within 34 digits and the valid range of exponents is the job of arithmetic. parse/1 applies those limits to the text of a number.

Summary

Functions

Parses the text of a number, as written by grammar rule 35 of DMN 1.6: an optional minus sign, digits with an optional fraction, and an optional exponent.

Rounds a coefficient with more than 34 digits to 34, half to even, and returns it with its exponent. A coefficient of 34 digits or fewer is returned as it is.

Returns the type descriptor of number.

Returns true for a Decimal that is a number of FEEL: finite, with a coefficient of at most 34 digits and an exponent inside the decimal128 range (Feel.Runtime.Number.valid?/1, D-214). A value that a host binds and that is not one is no number where a value is checked, as arithmetic refuses it.

Types

t()

@type t() :: Decimal.t()

Functions

parse(text)

@spec parse(String.t()) :: {:ok, t()} | :error

Parses the text of a number, as written by grammar rule 35 of DMN 1.6: an optional minus sign, digits with an optional fraction, and an optional exponent.

The scale of the text is kept: 1.50 stays 1.50. A value with more than 34 significant digits is rounded to 34, half to even. Returns :error when the text is not a number or its exponent is outside the decimal128 range. There is no negative zero: -0 is 0.

iex> Feel.Value.Number.parse("1.50")
{:ok, Decimal.new("1.50")}
iex> Feel.Value.Number.parse("-.5")
{:ok, Decimal.new("-0.5")}
iex> Feel.Value.Number.parse("1.2e3")
{:ok, Decimal.new("1.2E+3")}
iex> Feel.Value.Number.parse("5.")
:error
iex> Feel.Value.Number.parse("1e99999")
:error

round_to_digits(coefficient, exponent)

@spec round_to_digits(non_neg_integer(), integer()) :: {non_neg_integer(), integer()}

Rounds a coefficient with more than 34 digits to 34, half to even, and returns it with its exponent. A coefficient of 34 digits or fewer is returned as it is.

iex> Feel.Value.Number.round_to_digits(12, -1)
{12, -1}
iex> Feel.Value.Number.round_to_digits(10 ** 34 + 5, 0)
{10 ** 33, 1}
iex> Feel.Value.Number.round_to_digits(10 ** 34 + 15, 0)
{10 ** 33 + 2, 1}

type()

@spec type() :: Feel.Type.t()

Returns the type descriptor of number.

value?(term)

@spec value?(term()) :: boolean()

Returns true for a Decimal that is a number of FEEL: finite, with a coefficient of at most 34 digits and an exponent inside the decimal128 range (Feel.Runtime.Number.valid?/1, D-214). A value that a host binds and that is not one is no number where a value is checked, as arithmetic refuses it.

iex> Feel.Value.Number.value?(Decimal.new("1.5"))
true
iex> Feel.Value.Number.value?(Decimal.new("NaN"))
false
iex> Feel.Value.Number.value?(Decimal.new(1, 10_000_000_000_000_000_000_000_000_000_000_000, -34))
false
iex> Feel.Value.Number.value?(1.5)
false