float.fz
# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation. If not, see <https://www.gnu.org/licenses/>.
# -----------------------------------------------------------------------
#
# Tokiwa Software GmbH, Germany
#
# Source code of Fuzion standard library feature float
#
# Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------
# float -- floating point values
#
#
# float is the abstract parent of concrete floating point features such as
# f32 or f64.
#
public float : numeric is
# For IEEE_754, all operations are defined for all values.
# Hence there is no need to redefine any <op>! features.
#
# comparison
#
# This provides comparison operators using IEEE semantics.
#
# type.equality and type.lteq should be used for equivalence relations
# and total ordering in the mathematical sense.
#
public infix = (other float.this) bool => abstract
public infix != (other float.this) bool => !(infix = other)
public infix <= (other float.this) bool => abstract
public infix >= (other float.this) bool => abstract
public infix > (other float.this) bool => abstract
public infix < (other float.this) bool => abstract
# does this float value fit into an i64? This is redefined by children
# of float that support `as_i64`.
#
public fits_in_i64 => false
# convert a float value to i64 dropping any fraction.
# the value must be in the range of i64
#
public as_i64 i64
pre
safety: fits_in_i64
=> abstract
# convert a float value to i32 dropping any fraction.
# the value must be in the range of i32
#
public as_i32 => as_i64.as_i32
public fract float.this => abstract
# round floating point number
# ties to away (0.5 => 1; -0.5 => -1; etc.)
#
# NYI this could be made faster, see here:
# https://cs.opensource.google/go/go/+/refs/tags/go1.18.1:src/math/floor.go;l=79
public round float.this =>
if float.this < float.this.zero
-(-float.this).round
else if fract = float.this.zero
float.this
else
(float.this + float.this.one/float.this.two).floor
# floor: the greatest integer lower or equal to this
public floor float.this =>
if fract < float.this.zero
float.this - fract - float.this.one
else
float.this - fract
# ceiling: the smallest integer greater or equal to this
public ceil float.this =>
if fract ≤ float.this.zero
float.this - fract
else
float.this - fract + float.this.one
# number of bits used for mantissa,
# including leading '1' that is not actually stored
#
public type.significand_bits i32 => abstract
# number of bits used for exponent
#
public type.exponent_bits i32 => abstract
# the amount of bits that are used to encode the mantissa
public type.mantissa_bits => significand_bits - 1
# the biased exponent of this float
#
public exponent_biased i32 => abstract
# the normalized exponent of this float
#
public exponent i32 => abstract
# the normalized mantissa of this float
public mantissa u64 => abstract
# is the bit denoting the sign of the number set?
# this is different from smaller than zero since
# there is +0, -0, NaN, etc. in floating point numbers.
#
public is_sign_bit_set bool => abstract
# true when the absolute value
# is smaller than 0.001
# or greater than 9_999_999
#
public use_scientific_notation bool => abstract
# is not a number?
#
public is_NaN bool => abstract
# square root
#
public square_root float.this => abstract
# square root alias
#
public sqrt => square_root
# the `val`-th power of ℇ
# i.e. ℇᵛᵃˡ
#
public exp float.this => abstract
# logarithm with base ℇ
#
public log float.this => abstract
# trigonometric
public sin float.this => abstract
public cos float.this => abstract
public tan float.this => abstract
public asin float.this => abstract
public acos float.this => abstract
public atan float.this => abstract
# hyperbolicus
public sinh float.this => abstract
public cosh float.this => abstract
public tanh float.this => abstract
# area hyperbolicus
public asinh float.this =>
# ln(x+sqrt(x^2+1))
(float.this + (float.this ** float.this.type.two + float.this.type.one).sqrt).log
public acosh float.this =>
# ln(x+sqrt(x^2-1))
(float.this + (float.this ** float.this.type.two - float.this.type.one).sqrt).log
public atanh float.this =>
# 1/2*ln((1+x)/(1-x))
((float.this.type.one + float.this)/(float.this.type.one - float.this)).log / float.this.type.two
# number of bytes required to store this value
#
public type.bytes i32 => abstract
# number of bits required to store this value
#
public type.size => 8*bytes
# eulers number 2.72..
#
public type.ℇ float.this => abstract
# pi 3.14...
#
public type.π float.this => abstract
# conversion
#
# convert an i64 value to a floating point value
#
# if the value cannot be represented exactly, the result is either
# the nearest higher or nearest lower value
#
public type.from_i64(val i64) float.this => abstract
public type.exponent_range => -min_exp..max_exp
# non signaling not a number
#
public type.quiet_NaN => zero / zero
# not a number
#
public type.NaN => quiet_NaN
public type.negative_infinity => -one / zero
public type.positive_infinity => one / zero
# infinity
#
public type.infinity => positive_infinity
public type.min_exp i32 => abstract
public type.max_exp i32 => abstract
public type.min_positive float.this => abstract
public type.max float.this => abstract
public type.epsilon float.this => abstract
# logarithm with base `base`
#
public log (base float.this) float.this
pre safety: base > float.this.type.zero
=>
log / base.log
public type.atan2 (y, x float.this) float.this => abstract
# equality
#
# This provides an equivalence relation in the mathematical
# sense and therefore breaks the IEEE semantics. infix = should
# be used for IEEE semantics.
#
# The equivalence relation is provided by the usual comparison
# of floating-point numbers, with the definition of NaN = NaN.
#
public redef type.equality(a, b float.this) bool =>
a.infix = b || (a.is_NaN && b.is_NaN)
# total order
#
# This provides a total order in the mathematical sense and
# therefore breaks the IEEE semantics. infix <= should be
# used for IEEE semantics.
#
# The total order is provided by the usual comparison of
# floating-point numbers, with the definition that NaN <= x,
# for any x (including x = NaN).
#
public redef type.lteq(a, b float.this) bool =>
a.infix <= b || a.is_NaN
last changed: 2025-01-23