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


  # preconditions for basic operations: true if the operation's result is
  # representable for the given values.  For IEEE_754, all operations are
  # defined for all values.
  #
  public redef prefix +! bool => true
  public redef prefix -! bool => true
  public redef infix +! (other float.this) bool => true
  public redef infix -! (other float.this) bool => true
  public redef infix *! (other float.this) bool => true
  public redef infix /! (other float.this) bool => true
  public redef infix %! (other float.this) bool => true
  public redef infix **!(other float.this) bool => true


  # comparision
  #
  # This provides comparision 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


  # convert a float value to i64 dropping any fraction.
  # the value must be in the range of i64
  #
  public as_i64 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


  # 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


  # is not a number?
  #
  public type.is_NaN (val float.this) bool => abstract


  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


  # square root
  #
  public type.square_root (val float.this) float.this => abstract


  # square root alias
  #
  public type.sqrt (val float.this) => square_root val


  # the `val`-th power of ℇ
  # i.e. ℇᵛᵃˡ
  #
  public type.exp (val float.this) float.this => abstract


  # logarithm with base ℇ
  #
  public type.log (val float.this) float.this => abstract


  # logarithm with base `base`
  #
  public type.log (base, val float.this) float.this
  pre base > zero
  =>
    (float.this.log val) / (float.this.log base)


  # trigonometric

  public type.sin  (val float.this) float.this => abstract
  public type.cos  (val float.this) float.this => abstract
  public type.tan  (val float.this) float.this => abstract
  public type.asin (val float.this) float.this => abstract
  public type.acos (val float.this) float.this => abstract
  public type.atan (val float.this) float.this => abstract
  public type.atan2 (y, x float.this) float.this => abstract


  # hyperbolicus

  public type.sinh (val float.this) float.this => abstract
  public type.cosh (val float.this) float.this => abstract
  public type.tanh (val float.this) float.this => abstract


  # area hyperbolicus

  public type.asinh(val float.this) float.this =>
    # ln(x+sqrt(x^2+1))
    float.this.log (val + sqrt (val ** two + one))
  public type.acosh(val float.this) float.this =>
    # ln(x+sqrt(x^2-1))
    float.this.log (val + sqrt (val ** two - one))
  public type.atanh(val float.this) float.this =>
    # 1/2*ln((1+x)/(1-x))
    float.this.log ((one + val)/(one - val)) / two


  # 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 comparision
  # of floating-point numbers, with the definition of NaN = NaN.
  #
  public type.equality(a, b float.this) bool =>
    a.infix = b || (is_NaN a && is_NaN b)


  # 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 comparision of
  # floating-point numbers, with the definition that NaN <= x,
  # for any x (including x = NaN).
  #
  public type.lteq(a, b float.this) bool =>
    a.infix <= b || is_NaN a