Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

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