README

#MoonBit Float Package Documentation

This package provides operations on 32-bit floating-point numbers (Float). It includes basic arithmetic, trigonometric functions, exponential and logarithmic functions, as well as utility functions for rounding and conversion.

#Special Values

The package defines several special floating-point values:

///|
test "special float values" {
// Infinity values
inspect(@float.infinity, content="Infinity")
inspect(@float.neg_infinity, content="-Infinity")

// Not a Number
inspect(@float.not_a_number, content="NaN")

// Bounds
inspect(@float.max_value, content="3.4028234663852886e+38")
inspect(@float.min_value, content="-3.4028234663852886e+38")
inspect(@float.min_positive, content="1.1754943508222875e-38")
}

///|
test "checking special values" {
// Testing for special values
inspect(@float.infinity.is_inf(), content="true")
inspect(@float.neg_infinity.is_neg_inf(), content="true")
inspect(@float.infinity.is_pos_inf(), content="true")
inspect(@float.not_a_number.is_nan(), content="true")
}

#Rounding Functions

The package provides various ways to round floating-point numbers:

///|
test "rounding functions" {
// Ceiling - rounds up
inspect(@float.ceil(3.2), content="4")
inspect(@float.ceil(-3.2), content="-3")

// Floor - rounds down
inspect(@float.floor(3.2), content="3")
inspect(@float.floor(-3.2), content="-4")

// Round - rounds to nearest integer
inspect(@float.round(3.7), content="4")
inspect(@float.round(3.2), content="3")

// Truncate - removes decimal part
inspect(@float.trunc(3.7), content="3")
inspect(@float.trunc(-3.7), content="-3")
}

#Utility Functions

Other useful operations on floats:

///|
test "utility functions" {
// Absolute value
inspect(Float::abs(-3.14), content="3.140000104904175")

// Conversion to integer
inspect(3.14.to_int(), content="3")

// Default value
inspect((Default::default() : Float), content="0")
}

#Byte Representation

Functions to convert floats to their byte representation:

///|
test "byte representation" {
let x : Float = 3.14
// Big-endian bytes
let be_bytes = x.to_be_bytes()
// Little-endian bytes
let le_bytes = x.to_le_bytes()
inspect(be_bytes.length(), content="4")
inspect(le_bytes.length(), content="4")
}

#Math Functions

///|
test "math functions" {
inspect(Float::sqrt(9.0), content="3")
inspect(Float::signum(-5.0), content="-1")
inspect(Float::min(1.0, 2.0), content="1")
inspect(Float::max(1.0, 2.0), content="2")
}

#Clamping and Interpolation

///|
test "clamp and lerp" {
inspect(Float::clamp(5.0, min=0.0, max=3.0), content="3")
inspect(Float::clamp(-1.0, min=0.0, max=3.0), content="0")
inspect(Float::lerp(0.0, target=10.0, t=0.5), content="5")
}

#Approximate Comparison

///|
test "is_close" {
let a : Float = 0.1 + 0.2
inspect(Float::is_close(a, 0.3, relative_tolerance=1.0e-6), content="true")
}

#Type Conversions

Convert from other numeric types:

///|
test "conversions" {
inspect(Float::from_int(42), content="42")
inspect(Float::from_double(3.14), content="3.140000104904175")
inspect(Float::from_int64(100L), content="100")
inspect(Float::from_uint(42U), content="42")
inspect(Float::from_byte(b'\x41'), content="65")
inspect((3.14 : Float).to_double(), content="3.140000104904175")
inspect((3.14 : Float).to_int(), content="3")
}

#Bit Reinterpretation

Reinterpret the bit pattern of a float as an integer and vice versa (no conversion, just reinterpreting the 32 bits):

///|
test "reinterpret" {
let f : Float = 1.0
let bits = f.reinterpret_as_int()
inspect(bits, content="1065353216") // IEEE 754: 0x3F800000
let roundtrip = Float::reinterpret_from_int(bits)
inspect(roundtrip, content="1")
// unsigned variant
let ubits = f.reinterpret_as_uint()
inspect(ubits, content="1065353216")
let roundtrip2 = Float::reinterpret_from_uint(ubits)
inspect(roundtrip2, content="1")
}

#Range Iteration

///|
test "range" {
let values = Float::until(0.0, 1.0, step=0.5).to_array()
debug_inspect(values, content="[0, 0.5]")
let inclusive = Float::until(0.0, 1.0, step=0.5, inclusive=true).to_array()
debug_inspect(inclusive, content="[0, 0.5, 1]")
}

Float

Note

Float is a built-in type. The documentation may not be complete here. You can find all methods and implementations in the core/builtin and core/float package.

#
Float::abs

#as_free_fn(deprecated="Use Float::abs instead.")
fn Float::abs(self : Float) -> Float

Returns the absolute value of a floating-point number.

Parameters:

  • self : A floating-point number.

Returns the absolute value of the input number. For positive numbers and zero, returns the number unchanged. For negative numbers, returns the negation of the number. For NaN, returns NaN.

Example:

test {
inspect((1.5 : Float).abs(), content="1.5")
inspect((-1.5 : Float).abs(), content="1.5")
inspect((0.0 : Float).abs(), content="0")
inspect((-0.0 : Float).abs(), content="0")
inspect(@float.not_a_number.abs().is_nan(), content="true")
}

#
Float::add

fn Float::add(self : Float, other : Float) -> Float

#
Float::ceil

#as_free_fn
fn Float::ceil(self : Float) -> Float

Returns the smallest integer greater than or equal to a given floating-point number.

Parameters:

  • value : The floating-point number to be rounded up.

Returns a floating-point number representing the ceiling value.

Example:

test {
inspect((1.5 : Float).ceil(), content="2")
inspect((1.0 : Float).ceil(), content="1")
inspect((-1.5 : Float).ceil(), content="-1")
}

#
Float::clamp

fn Float::clamp(self : Float, min~ : Float, max~ : Float) -> Float

Clamps the value between min and max (inclusive).

Parameters:

  • self : The value to clamp.
  • min : The lower bound of the range.
  • max : The upper bound of the range.

Returns min if self < min, max if self > max, and self otherwise.

Example:

test {
inspect((0.5 : Float).clamp(min=0.0, max=1.0), content="0.5")
inspect((-1.0 : Float).clamp(min=0.0, max=1.0), content="0")
inspect((2.0 : Float).clamp(min=0.0, max=1.0), content="1")
}

#
Float::compare

fn Float::compare(self : Float, other : Float) -> Int

#
Float::div

fn Float::div(self : Float, other : Float) -> Float

#
Float::equal

fn Float::equal(self : Float, other : Float) -> Bool

#
Float::floor

#as_free_fn
fn Float::floor(self : Float) -> Float

Returns the largest integer value less than or equal to the given floating-point number.

Parameters:

  • self : The floating-point number to be floored.

Returns a floating-point number representing the largest integer less than or equal to the input.

Example:

test {
inspect((1.7 : Float).floor(), content="1")
inspect((-1.7 : Float).floor(), content="-2")
inspect((2.0 : Float).floor(), content="2")
}

#
Float::from_byte

fn Float::from_byte(self : Byte) -> Float

Converts a byte value to a 32-bit floating-point number (IEEE 754 single-precision format). The byte value is treated as an unsigned 8-bit integer during the conversion.

Parameters:

  • byte : The byte value to be converted to a float.

Returns a 32-bit floating-point number representing the byte value.

Example:

test {
let b = b'\xFF' // 255 in decimal
let f = Float::from_byte(b)
// Convert to double for comparison since Float doesn't implement Show
inspect(f.to_double(), content="255")
}

#
Float::from_double

fn Float::from_double(self : Double) -> Float

Converts a double-precision floating-point number to a single-precision floating-point number. The conversion may result in a loss of precision due to the reduced number of bits available in the single-precision format.

Parameters:

  • value : The double-precision floating-point number to be converted.

Returns a single-precision floating-point number that represents the closest possible value to the input double-precision number.

Example:

test {
let d = 3.14159265359
inspect(Float::from_double(d).to_double(), content="3.1415927410125732") // Note the loss of precision
}

#
Float::from_int

fn Float::from_int(self : Int) -> Float

Converts an integer to a 32-bit floating-point number. The conversion is exact for small integers, but may lose precision for large integers due to the limited precision of the floating-point format.

Parameters:

  • number : The integer value to be converted to a floating-point number.

Returns a 32-bit floating-point number representing the same value as the input integer.

Example:

test {
let n = 42
let f = Float::from_int(n)
// Convert back to double for comparison since Float doesn't implement Show
inspect(f.to_double(), content="42")
}

#
Float::from_int64

fn Float::from_int64(self : Int64) -> Float

Converts a 64-bit integer to a 32-bit floating-point number. The conversion may result in loss of precision due to the limited precision of the 32-bit floating-point format.

Parameters:

  • self : The 64-bit integer value to be converted.

Returns a 32-bit floating-point number that represents the input integer value. Note that for values outside the range of representable 32-bit floating-point numbers, the result will be rounded to the nearest representable value.

Example:

test {
let n = 42L
let f = Float::from_int64(n)
// Convert to double for comparison since Float doesn't implement Show
inspect(f.to_double(), content="42")
}
Create from int64.

#
Float::from_uint

fn Float::from_uint(self : UInt) -> Float

Converts an unsigned 32-bit integer to a single-precision floating-point number. Due to the limited precision of the 32-bit floating-point format, values above 16777216 (2^24) may lose precision during conversion.

Parameters:

  • self : The unsigned 32-bit integer to be converted.

Returns a 32-bit floating-point number that represents the same numerical value as the input unsigned integer.

Example:

test {
let n = 42U
inspect(Float::from_uint(n).to_double(), content="42")
let big = 16777216U // 2^24
inspect(Float::from_uint(big).to_double(), content="16777216") // Last precisely representable integer
}

#
Float::from_uint64

fn Float::from_uint64(self : UInt64) -> Float

Converts an unsigned 64-bit integer to a 32-bit floating-point number. Due to floating-point precision limitations, the conversion may lose precision if the integer value is too large to be represented exactly as a float.

Parameters:

  • self : The unsigned 64-bit integer to be converted.

Returns a 32-bit floating-point number that represents the input value. If the input value is too large to be represented exactly, the result will be rounded to the nearest representable float value.

Example:

test {
let n = 42UL
inspect(Float::from_uint64(n).to_double(), content="42")
let big = 18446744073709551615UL // UInt64::max_value
inspect(Float::from_uint64(big).to_double(), content="18446744073709552000")
}
Create from uint64.

#
Float::hash

fn Float::hash(self : Float) -> Int

#
Float::is_close

fn Float::is_close(self : Float, other : Float, relative_tolerance? : Float, absolute_tolerance? : Float) -> Bool

Determines whether two floating-point numbers are approximately equal within specified tolerances. The implementation follows the algorithm described in PEP 485 for Python's math.isclose().

Parameters:

  • self : The first floating-point number to compare.
  • other : The second floating-point number to compare.
  • relative_tolerance : The relative tolerance for the comparison. Must be non-negative. Defaults to 1e-9.
  • absolute_tolerance : The absolute tolerance for the comparison. Must be non-negative. Defaults to 0.0.

Returns whether the two numbers are considered approximately equal. Returns true if the numbers are exactly equal or if they are within either the relative or absolute tolerance. Returns false if either number is infinite.

Example:

test {
let x = 1.0
let y = 1.000000001
inspect(x.is_close(y), content="false")
inspect(x.is_close(y, relative_tolerance=1.0e-10), content="false")
inspect(@float.infinity.is_close(@float.infinity), content="true")
}

#
Float::is_inf

fn Float::is_inf(self : Float) -> Bool

Determines if the floating-point number is positive or negative infinity.

Parameters:

  • self : The floating-point number to be checked.

Returns a boolean value indicating whether the number is positive or negative infinity.

Example:

test {
inspect(@float.infinity.is_inf(), content="true")
inspect(@float.neg_infinity.is_inf(), content="true")
inspect((1.0 : Float).is_inf(), content="false")
}

#
Float::is_nan

fn Float::is_nan(self : Float) -> Bool

Determines if the floating-point number is NaN (Not a Number).

Parameters:

  • self : The floating-point number to be checked.

Returns a boolean value indicating whether the number is NaN.

Example:

test {
inspect(@float.not_a_number.is_nan(), content="true")
inspect((1.0 : Float).is_nan(), content="false")
inspect(@float.infinity.is_nan(), content="false")
}

#
Float::is_neg_inf

fn Float::is_neg_inf(self : Float) -> Bool

Determines if the floating-point number is negative infinity.

Parameters:

  • self : The floating-point number to be checked.

Returns a boolean value indicating whether the number is negative infinity.

Example:

test {
inspect(@float.neg_infinity.is_neg_inf(), content="true")
inspect((1.0 : Float).is_neg_inf(), content="false")
inspect(@float.infinity.is_neg_inf(), content="false")
}

#
Float::is_pos_inf

fn Float::is_pos_inf(self : Float) -> Bool

Determines if the floating-point number is positive infinity.

Parameters:

  • self : The floating-point number to be checked.

Returns a boolean value indicating whether the number is positive infinity.

Example:

test {
inspect(@float.infinity.is_pos_inf(), content="true")
inspect((1.0 : Float).is_pos_inf(), content="false")
inspect(@float.neg_infinity.is_pos_inf(), content="false")
}

#
Float::lerp

fn Float::lerp(self : Float, target~ : Float, t~ : Float) -> Float

Performs linear interpolation from self to target by factor t.

The interpolation formula is self + (target - self) * t.

Parameters:

  • self : The start value.
  • target : The end value.
  • t : The interpolation factor.

Returns the interpolated value.

Example:

test {
inspect((0.0 : Float).lerp(target=10.0, t=0.25), content="2.5")
inspect((5.0 : Float).lerp(target=15.0, t=0.0), content="5")
inspect((5.0 : Float).lerp(target=15.0, t=1.0), content="15")
}

#
Float::max

fn Float::max(self : Float, other : Float) -> Float

Returns the maximum of two floating-point values.

If exactly one argument is NaN, returns the other argument.

#
Float::min

fn Float::min(self : Float, other : Float) -> Float

Returns the minimum of two floating-point values.

If exactly one argument is NaN, returns the other argument.

#
Float::mod

fn Float::mod(self : Float, other : Float) -> Float

#
Float::mul

fn Float::mul(self : Float, other : Float) -> Float

#
Float::neg

fn Float::neg(self : Float) -> Float

#
Float::pow

#as_free_fn(deprecated="Use `@math.powf` instead")
#deprecated("Use `@math.powf` instead")
fn Float::pow(self : Float, other : Float) -> Float

Calculates the power of a floating-point number raised to another floating-point number.

Parameters:

  • base : The base number to be raised to a power.
  • exponent : The power to which the base number is raised.

Returns the result of raising base to the power of exponent.

Example:

test {
inspect(@math.powf(2.0, 3.0), content="8")
inspect(@math.powf(4.0, 0.5), content="2")
inspect(@math.powf(1.0, -1.0), content="1")
}

#
Float::reinterpret_as_int

fn Float::reinterpret_as_int(self : Float) -> Int

Reinterprets the bits of a 32-bit floating-point number as a 32-bit signed integer without performing any numeric conversion. The bit pattern is preserved exactly, only the type interpretation changes.

Parameters:

  • self : The 32-bit floating-point number whose bits are to be reinterpreted.

Returns a 32-bit signed integer that has the same bit pattern as the input floating-point number.

Example:

test {
let f = Float::from_double(1.0)
// IEEE 754 representation of 1.0 is 0x3F800000
inspect(f.reinterpret_as_int(), content="1065353216")
}

#
Float::reinterpret_as_uint

fn Float::reinterpret_as_uint(self : Float) -> UInt

Reinterprets the bits of a 32-bit floating-point number as an unsigned 32-bit integer without performing any numeric conversion. Preserves the exact bit pattern of the input value, only changing how these bits are interpreted.

Parameters:

  • float : The 32-bit floating-point number whose bits are to be reinterpreted.

Returns an unsigned 32-bit integer (UInt) that has the same bit pattern as the input floating-point number.

Example:

test {
let x : Float = 1.0
inspect(x.reinterpret_as_uint(), content="1065353216") // Decimal representation of 0x3F800000
}

#
Float::reinterpret_from_int

fn Float::reinterpret_from_int(self : Int) -> Float

Reinterprets the bits of a 32-bit integer as a single-precision floating-point number according to IEEE 754 standard. The bit pattern of the input is preserved, only the type interpretation changes.

Parameters:

  • self : The 32-bit integer whose bits are to be reinterpreted as a single-precision floating-point number.

Returns a 32-bit floating-point number (Float) that has the same bit pattern as the input integer.

Example:

test {
// 0x3F800000 represents 1.0 in IEEE 754 single-precision format
let n = 1065353216 // 0x3F800000
inspect(Float::reinterpret_from_int(n), content="1")
}

#
Float::reinterpret_from_uint

fn Float::reinterpret_from_uint(self : UInt) -> Float

Reinterprets the bits of an unsigned 32-bit integer as a single-precision floating-point number (IEEE 754). The bit pattern is preserved exactly, only the type interpretation changes.

Parameters:

  • self : The unsigned 32-bit integer whose bits are to be reinterpreted as a single-precision floating-point number.

Returns a single-precision floating-point number (Float) whose bit pattern is identical to the input integer.

Example:

test {
let n = 0x3F800000U // Bit pattern for 1.0f
inspect(Float::reinterpret_from_uint(n), content="1")
}

#
Float::round

#as_free_fn
fn Float::round(self : Float) -> Float

Rounds a floating-point number to the nearest integer value, with ties rounding up (towards positive infinity).

Parameters:

  • number : The floating-point number to be rounded.

Returns a floating-point number representing the rounded value.

Example:

test {
inspect((2.3 : Float).round(), content="2")
inspect((2.5 : Float).round(), content="3")
inspect((-2.5 : Float).round(), content="-2")
}

#
Float::signum

fn Float::signum(self : Float) -> Float

Returns the sign of the float.
  • If the float is positive, returns 1.0.
  • If the float is negative, returns -1.0.
  • Otherwise, returns the float itself (0.0, -0.0 and NaN).

#
Float::sqrt

fn Float::sqrt(self : Float) -> Float

Calculates the square root of a floating-point number. For non-negative numbers, returns the principal square root. For negative numbers or NaN, returns NaN.

Parameters:

  • self : The floating-point number whose square root is to be calculated.

Returns a 32-bit floating-point number representing the square root of the input value:

  • For a positive number, returns its principal square root
  • For zero (positive or negative), returns zero with the same sign
  • For NaN or negative numbers, returns NaN

Example:

test {
let x = Float::from_double(16.0)
let root = x.sqrt()
inspect(root.to_double(), content="4")
let neg = Float::from_double(-4.0)
let neg_root = neg.sqrt()
inspect(neg_root.to_double(), content="NaN")
}

#
Float::sub

fn Float::sub(self : Float, other : Float) -> Float

#
Float::to_be_bytes

fn Float::to_be_bytes(self : Float) -> Bytes

Converts a floating-point number to a sequence of bytes in big-endian byte order. In big-endian order, the most significant byte is stored at the lowest memory address.

Parameters:

  • float : The floating-point number to be converted.

Returns a sequence of 4 bytes representing the floating-point number in IEEE 754 single-precision format with big-endian byte order.

Example:

test {
let x : Float = 1.0
inspect(
x.to_be_bytes(),
content=(
#|b"?\x80\x00\x00"
),
)
}

#
Float::to_double

fn Float::to_double(self : Float) -> Double

Converts a 32-bit floating-point number to a double-precision (64-bit) floating-point number.

Parameters:

  • self : The 32-bit floating-point number to be converted.

Returns a double-precision floating-point number that preserves the exact value of the input. Since double-precision has more bits than single-precision, this conversion is always exact and never loses precision.

Example:

test {
let f = Float::from_double(3.14)
inspect(f.to_double(), content="3.140000104904175")
}

#
Float::to_int

fn Float::to_int(self : Float) -> Int

Converts a floating-point number to an integer, with proper handling of special cases such as NaN and values outside the range of 32-bit integers.

Parameters:

  • self : The floating-point number to be converted.

Returns an integer representation of the float value. Specifically:
  • 0 for @float.not_a_number (NaN),
  • @int.MAX_VALUE (2147483647) for values greater than @int.MAX_VALUE,
  • @int.MIN_VALUE (-2147483648) for values less than @int.MIN_VALUE.
  • truncated (towards zero) integer value for other cases.

Examples:

test {
inspect((1.5 : Float).to_int(), content="1")
inspect((-1.5 : Float).to_int(), content="-1")
inspect(@float.not_a_number.to_int(), content="0")
inspect(@float.infinity.to_int(), content="2147483647")
inspect(@float.neg_infinity.to_int(), content="-2147483648")
}

#
Float::to_json

fn Float::to_json(self : Float) -> Json

#
Float::to_le_bytes

fn Float::to_le_bytes(self : Float) -> Bytes

Converts a floating-point number to its binary representation in little-endian byte order.

Parameters:

  • float : The floating-point number to be converted.

Returns a sequence of bytes representing the float value in little-endian order (least significant byte first).

Example:

test {
let f : Float = 1.0
let bytes = f.to_le_bytes()
inspect(bytes.length(), content="4")
}

#
Float::to_string

fn Float::to_string(self : Float) -> String

#
Float::trunc

#as_free_fn
fn Float::trunc(self : Float) -> Float

Returns the truncated value of a floating-point number by removing its fractional part.

Parameters:

  • value : The floating-point number to be truncated.

Returns the truncated floating-point number. Specifically:

  • Returns 0.0 (with the same sign as input) for values between -1.0 and 1.0
  • Returns the input unchanged for integer values or values too large to have fractional parts
  • Returns the integer part for other values

Example:

test {
inspect((3.7 : Float).trunc(), content="3")
inspect((-3.7 : Float).trunc(), content="-3")
inspect((0.2 : Float).trunc(), content="0")
}

#
Float::until

fn Float::until(self : Float, end : Float, step? : Float, inclusive? : Bool) -> Iter[Float]

Creates an iterator that iterates over a range of Float with default step 1.0 . To grow the range downward, set the step parameter to a negative value.

Arguments

  • start - The starting value of the range (inclusive).
  • end - The ending value of the range (exclusive by default).
  • step - The step size of the range (default 1.0).
  • inclusive - Whether the ending value is inclusive (default false).

Returns

Returns an iterator that iterates over the range of Float from start to end - 1.
impl Add for Float
impl Compare for Float
impl Default for Float
impl Div for Float
impl Eq for Float
impl Hash for Float
impl Mod for Float
impl Mul for Float
impl Neg for Float
impl Show for Float
impl Sub for Float
impl ToJson for Float

#
default

#deprecated("This function is deprecated.")
fn default() -> Float

Returns the default value for Float type, which is 0.0.

Returns a float value of 0.0.

#
infinity

let infinity : Float

Represents positive infinity as a floating-point value.

Returns a constant value representing positive infinity in IEEE 754 single-precision floating-point format (0x7F800000).

Example:

test {
inspect(@float.infinity.is_pos_inf(), content="true")
inspect(@float.infinity > 1.0, content="true")
}

#
max_value

let max_value : Float

Represents the maximum finite value of a 32-bit floating-point number, which is approximately 3.4028235e+38.

Example:

test {
inspect(@float.max_value < @float.infinity, content="true")
inspect(@float.max_value > 0.0, content="true")
}

#
min_positive

let min_positive : Float

Represents the smallest positive normalized floating-point number that can be represented by the Float type (approximately 1.17549435e-38).

Example:

test {
inspect(@float.min_positive > 0.0, content="true")
inspect(@float.min_positive < 1.2e-38, content="true")
}

#
min_value

let min_value : Float

Represents the smallest finite negative Float value (-3.4028235e+38).

Example:

test {
inspect(@float.min_value < -1.0, content="true")
inspect(@float.min_value > @float.neg_infinity, content="true")
}

#
neg_infinity

let neg_infinity : Float

Represents negative infinity for 32-bit floating-point numbers. This constant has a mathematical value of -∞ and follows the IEEE 754 standard for floating-point arithmetic.

Returns a Float value representing negative infinity.

Example:

test {
inspect(@float.neg_infinity.is_neg_inf(), content="true")
inspect(@float.neg_infinity < (-1.0 : Float), content="true")
}

#
not_a_number

let not_a_number : Float

Represents the Not a Number (NaN) value in floating-point arithmetic. NaN is used to represent undefined or unrepresentable values, such as the result of 0.0/0.0.

Returns a special floating-point value that represents NaN.

Example:

test {
inspect(@float.not_a_number.is_nan(), content="true")
inspect(@float.not_a_number + 1.0, content="NaN")
}