Nx.Type (Nx v0.1.0) View Source

Conveniences for working with types.

A type is a two-element tuple with the name and the size. The respective sizes for the types are the following:

* `:s` - signed integer (8, 16, 32, 64)
* `:u` - unsigned integer (8, 16, 32, 64)
* `:f` - float (16, 32, 64)
* `:bf` - a brain floating point (16)

Note: there is a special type used by the defn compiler which is {:tuple, size}, that represents a tuple. Said types do not appear on user code, only on compiler implementations, and therefore are not handled by the functions in this module.

Link to this section Summary

Functions

Casts the given number to type.

Returns true if the type is a float in Elixir.

Infers the type of the given value.

Returns true if the type is an integer in Elixir.

Returns the maximum possible value for the given type.

Merges the given types finding a suitable representation for both.

Merges the given types with the type of a number.

Returns the minimum possible value for the given type.

Validates the given type tuple.

Converts the given type to an aggregation precision.

Converts the given type to a floating point representation with the minimum size necessary.

Returns a string representation of the given type.

Link to this section Types

Specs

t() ::
  {:s, 8}
  | {:s, 16}
  | {:s, 32}
  | {:s, 64}
  | {:u, 8}
  | {:u, 16}
  | {:u, 32}
  | {:u, 64}
  | {:f, 16}
  | {:f, 32}
  | {:f, 64}
  | {:bf, 16}
  | {:tuple, non_neg_integer()}

Link to this section Functions

Casts the given number to type.

It does not handle overflow/underflow, returning the number as is, but cast.

Examples

iex> Nx.Type.cast_number!({:u, 8}, 10)
10
iex> Nx.Type.cast_number!({:s, 8}, 10)
10
iex> Nx.Type.cast_number!({:s, 8}, -10)
-10
iex> Nx.Type.cast_number!({:f, 32}, 10)
10.0
iex> Nx.Type.cast_number!({:bf, 16}, -10)
-10.0

iex> Nx.Type.cast_number!({:f, 32}, 10.0)
10.0
iex> Nx.Type.cast_number!({:bf, 16}, -10.0)
-10.0

iex> Nx.Type.cast_number!({:u, 8}, -10)
** (ArgumentError) cannot cast number -10 to {:u, 8}

iex> Nx.Type.cast_number!({:s, 8}, 10.0)
** (ArgumentError) cannot cast number 10.0 to {:s, 8}

Returns true if the type is a float in Elixir.

Examples

iex> Nx.Type.float?({:f, 32})
true
iex> Nx.Type.float?({:bf, 16})
true
iex> Nx.Type.float?({:u, 64})
false

Infers the type of the given value.

The value may be a number, boolean, or an arbitrary list with any of the above. Integers are by default signed and of size 64. Floats have size of 64. Booleans are unsigned integers of size 1 (also known as predicates).

In case mixed types are given, the one with highest space requirements is used (i.e. float > brain floating > integer > boolean).

Examples

iex> Nx.Type.infer([1, 2, 3])
{:s, 64}
iex> Nx.Type.infer([[1, 2], [3, 4]])
{:s, 64}

iex> Nx.Type.infer([1.0, 2.0, 3.0])
{:f, 32}
iex> Nx.Type.infer([1, 2.0])
{:f, 32}

iex> Nx.Type.infer([])
{:f, 32}

iex> Nx.Type.infer("string")
** (ArgumentError) cannot infer the numerical type of "string"

Returns true if the type is an integer in Elixir.

Examples

iex> Nx.Type.integer?({:s, 8})
true
iex> Nx.Type.integer?({:u, 64})
true
iex> Nx.Type.integer?({:f, 64})
false

Returns the maximum possible value for the given type.

Merges the given types finding a suitable representation for both.

Types have the following precedence:

f > bf > s > u

If the types are the same, they are merged to the highest size. If they are different, the one with the highest precedence wins, as long as the size of the max(big, small * 2)) fits under 64 bits. Otherwise it casts to f64.

Examples

iex> Nx.Type.merge({:s, 8}, {:s, 8})
{:s, 8}
iex> Nx.Type.merge({:s, 8}, {:s, 64})
{:s, 64}

iex> Nx.Type.merge({:s, 8}, {:u, 8})
{:s, 16}
iex> Nx.Type.merge({:s, 16}, {:u, 8})
{:s, 16}
iex> Nx.Type.merge({:s, 8}, {:u, 16})
{:s, 32}
iex> Nx.Type.merge({:s, 32}, {:u, 8})
{:s, 32}
iex> Nx.Type.merge({:s, 8}, {:u, 32})
{:s, 64}
iex> Nx.Type.merge({:s, 64}, {:u, 8})
{:s, 64}
iex> Nx.Type.merge({:s, 8}, {:u, 64})
{:s, 64}

iex> Nx.Type.merge({:u, 8}, {:f, 32})
{:f, 32}
iex> Nx.Type.merge({:u, 64}, {:f, 32})
{:f, 32}
iex> Nx.Type.merge({:s, 8}, {:f, 32})
{:f, 32}
iex> Nx.Type.merge({:s, 64}, {:f, 32})
{:f, 32}

iex> Nx.Type.merge({:u, 8}, {:f, 64})
{:f, 64}
iex> Nx.Type.merge({:u, 64}, {:f, 64})
{:f, 64}
iex> Nx.Type.merge({:s, 8}, {:f, 64})
{:f, 64}
iex> Nx.Type.merge({:s, 64}, {:f, 64})
{:f, 64}

iex> Nx.Type.merge({:u, 8}, {:bf, 16})
{:bf, 16}
iex> Nx.Type.merge({:u, 64}, {:bf, 16})
{:bf, 16}
iex> Nx.Type.merge({:s, 8}, {:bf, 16})
{:bf, 16}
iex> Nx.Type.merge({:s, 64}, {:bf, 16})
{:bf, 16}

iex> Nx.Type.merge({:f, 32}, {:bf, 16})
{:f, 32}
iex> Nx.Type.merge({:f, 64}, {:bf, 16})
{:f, 64}
Link to this function

merge_number(arg1, integer)

View Source

Merges the given types with the type of a number.

We attempt to keep the original type and its size as best as possible.

Examples

iex> Nx.Type.merge_number({:u, 8}, 0)
{:u, 8}
iex> Nx.Type.merge_number({:u, 8}, 255)
{:u, 8}
iex> Nx.Type.merge_number({:u, 8}, 256)
{:u, 16}
iex> Nx.Type.merge_number({:u, 8}, -1)
{:s, 16}
iex> Nx.Type.merge_number({:u, 8}, -32767)
{:s, 16}
iex> Nx.Type.merge_number({:u, 8}, -32768)
{:s, 16}
iex> Nx.Type.merge_number({:u, 8}, -32769)
{:s, 32}

iex> Nx.Type.merge_number({:s, 8}, 0)
{:s, 8}
iex> Nx.Type.merge_number({:s, 8}, 127)
{:s, 8}
iex> Nx.Type.merge_number({:s, 8}, -128)
{:s, 8}
iex> Nx.Type.merge_number({:s, 8}, 128)
{:s, 16}
iex> Nx.Type.merge_number({:s, 8}, -129)
{:s, 16}
iex> Nx.Type.merge_number({:s, 8}, 1.0)
{:f, 32}
iex> Nx.Type.merge_number({:u, 64}, -1337)
{:s, 64}

iex> Nx.Type.merge_number({:f, 32}, 1)
{:f, 32}
iex> Nx.Type.merge_number({:f, 32}, 1.0)
{:f, 32}
iex> Nx.Type.merge_number({:f, 64}, 1.0)
{:f, 64}

Returns the minimum possible value for the given type.

Validates the given type tuple.

It returns the type itself or raises.

Examples

iex> Nx.Type.normalize!({:u, 8})
{:u, 8}

iex> Nx.Type.normalize!({:u, 0})
** (ArgumentError) invalid numerical type: {:u, 0} (see Nx.Type docs for all supported types)

iex> Nx.Type.normalize!({:k, 8})
** (ArgumentError) invalid numerical type: {:k, 8} (see Nx.Type docs for all supported types)

Converts the given type to an aggregation precision.

Examples

iex> Nx.Type.to_aggregate({:s, 8})
{:s, 64}
iex> Nx.Type.to_aggregate({:u, 32})
{:u, 64}
iex> Nx.Type.to_aggregate({:bf, 16})
{:bf, 16}
iex> Nx.Type.to_aggregate({:f, 32})
{:f, 32}

Converts the given type to a floating point representation with the minimum size necessary.

Note both float and complex are floating point representations.

Examples

iex> Nx.Type.to_floating({:s, 8})
{:f, 32}
iex> Nx.Type.to_floating({:s, 32})
{:f, 32}
iex> Nx.Type.to_floating({:bf, 16})
{:bf, 16}
iex> Nx.Type.to_floating({:f, 32})
{:f, 32}

Returns a string representation of the given type.

Examples

iex> Nx.Type.to_string({:s, 8})
"s8"
iex> Nx.Type.to_string({:s, 16})
"s16"
iex> Nx.Type.to_string({:s, 32})
"s32"
iex> Nx.Type.to_string({:s, 64})
"s64"
iex> Nx.Type.to_string({:u, 8})
"u8"
iex> Nx.Type.to_string({:u, 16})
"u16"
iex> Nx.Type.to_string({:u, 32})
"u32"
iex> Nx.Type.to_string({:u, 64})
"u64"
iex> Nx.Type.to_string({:f, 16})
"f16"
iex> Nx.Type.to_string({:bf, 16})
"bf16"
iex> Nx.Type.to_string({:f, 32})
"f32"
iex> Nx.Type.to_string({:f, 64})
"f64"