wasm_num (wasm v0.1.0)

View Source

Conversion between IEEE 754 bit patterns and the runtime float representation.

Read this when a float coming out of a module is not the shape you expected. Erlang cannot hold NaN or Infinity in a float. Arithmetic that would produce one raises badarith, and <<F:64/float>> does not even match the bit patterns 7FF0... or 7FF8.... WebAssembly requires both, including NaN payload propagation, so floats use a hybrid representation:

  • finite values are Erlang floats, which is the fast and common case;
  • infinity and neg_infinity are atoms;
  • NaN is {nan, Sign, Payload}, keeping the payload bits that the specification's NaN propagation rules make observable. Signed zero needs no special case: since OTP 27 -0.0 =/= 0.0 and <<(-0.0):64/float>> produces the correct sign bit, so Erlang models it natively.

Arithmetic over this representation lives in wasm_num_f32 and wasm_num_f64. This module is only the boundary with bit patterns: constants in the binary format, reinterpret instructions, and linear memory loads and stores.

Summary

Functions

The NaN the specification requires an operation to produce when it makes one.

A 32-bit IEEE 754 bit pattern as a runtime float.

The inverse of f32_from_bits/1. NaN payload and sign survive the round trip.

As f32_to_bits/1, at 64 bits.

Whether this is an ordinary value, which is exactly when it is an Erlang float.

Whether this is either infinity.

Whether this is a NaN. Never true of an Erlang float, which cannot be one.

Reinterpret a signed value as unsigned, for the _u operations.

Reinterpret a signed value as unsigned, at 64 bits.

Reduce to the signed 32-bit range, wrapping like two's complement.

Reduce to the signed 64-bit range, wrapping like two's complement.

Reduce to the unsigned 32-bit range.

Reduce to the unsigned 64-bit range.

Types

f32()

-type f32() :: float() | fspecial().

f64()

-type f64() :: float() | fspecial().

fspecial()

-type fspecial() :: infinity | neg_infinity | {nan, Sign :: 0 | 1, Payload :: non_neg_integer()}.

Functions

f32_canonical_nan()

-spec f32_canonical_nan() -> f32().

The NaN the specification requires an operation to produce when it makes one.

f32_from_bits/1

-spec f32_from_bits(non_neg_integer()) -> f32().

A 32-bit IEEE 754 bit pattern as a runtime float.

Total: every one of the 2^32 patterns has an answer. An exponent of all ones becomes infinity, neg_infinity or {nan, Sign, Payload}, because an Erlang float cannot hold those. Everything else is an Erlang float.

f32_to_bits/1

-spec f32_to_bits(f32()) -> non_neg_integer().

The inverse of f32_from_bits/1. NaN payload and sign survive the round trip.

f64_canonical_nan()

-spec f64_canonical_nan() -> f64().

As f32_canonical_nan/0, at 64 bits.

f64_from_bits/1

-spec f64_from_bits(non_neg_integer()) -> f64().

As f32_from_bits/1, at 64 bits.

f64_to_bits/1

-spec f64_to_bits(f64()) -> non_neg_integer().

As f32_to_bits/1, at 64 bits.

is_finite(F)

-spec is_finite(f32() | f64()) -> boolean().

Whether this is an ordinary value, which is exactly when it is an Erlang float.

is_infinite/1

-spec is_infinite(f32() | f64()) -> boolean().

Whether this is either infinity.

is_nan/1

-spec is_nan(f32() | f64()) -> boolean().

Whether this is a NaN. Never true of an Erlang float, which cannot be one.

to_u32/1

-spec to_u32(integer()) -> non_neg_integer().

Reinterpret a signed value as unsigned, for the _u operations.

to_u64/1

-spec to_u64(integer()) -> non_neg_integer().

Reinterpret a signed value as unsigned, at 64 bits.

wrap_s32(V)

-spec wrap_s32(integer()) -> integer().

Reduce to the signed 32-bit range, wrapping like two's complement.

wrap_s64(V)

-spec wrap_s64(integer()) -> integer().

Reduce to the signed 64-bit range, wrapping like two's complement.

wrap_u32(V)

-spec wrap_u32(integer()) -> non_neg_integer().

Reduce to the unsigned 32-bit range.

wrap_u64(V)

-spec wrap_u64(integer()) -> non_neg_integer().

Reduce to the unsigned 64-bit range.