Fuzion Logo
flang.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 is true
  public redef prefix -! bool is true
  public redef infix +! (other float.this) bool is true
  public redef infix -! (other float.this) bool is true
  public redef infix *! (other float.this) bool is true
  public redef infix /! (other float.this) bool is true
  public redef infix %! (other float.this) bool is true
  public redef infix **!(other float.this) bool is 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 is abstract
  public infix != (other float.this) bool is !(infix = other)
  public infix <= (other float.this) bool is abstract
  public infix >= (other float.this) bool is abstract
  public infix > (other float.this) bool is abstract
  public infix < (other float.this) bool is abstract


  # convert a float value to i64 dropping any fraction.
  # the value must be in the range of i64
  #
  public as_i64 i64 is 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 is 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 is
    if float.this < float.this.type.zero
      -(-float.this).round
    else if fract = float.this.type.zero
      float.this
    else
      (float.this + float.this.type.one/float.this.type.two).floor


  # floor: the greatest integer lower or equal to this
  public floor float.this is
    if fract < float.this.type.zero
      float.this - fract - float.this.type.one
    else
      float.this - fract


  # ceiling: the smallest integer greater or equal to this
  public ceil float.this is
    if fract ≤ float.this.type.zero
      float.this - fract
    else
      float.this - fract + float.this.type.one


  # number of bits used for mantissa,
  # including leading '1' that is not actually stored
  #
  public type.significand_bits i32 is abstract

  # number of bits used for exponent
  #
  public type.exponent_bits i32 is 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 is abstract


  # the normalized exponent of this float
  #
  public exponent i32 is abstract


  # the normalized mantissa of this float
  public mantissa u64 is 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 is abstract


  # true when the absolute value
  # is smaller than 0.001
  # or greater than 9_999_999
  #
  public use_scientific_notation bool is abstract


  # number of bytes required to store this value
  #
  public type.bytes i32 is abstract


  # number of bits required to store this value
  #
  public type.size => 8*bytes


  # eulers number 2.72..
  #
  public type.ℇ float.this is abstract


  # pi 3.14...
  #
  public type.π float.this is 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 is 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 is abstract


  public type.negative_infinity => -one / zero


  public type.positive_infinity => one / zero


  # infinity
  #
  public type.infinity => positive_infinity


  public type.min_exp i32 is abstract
  public type.max_exp i32 is abstract
  public type.min_positive float.this is abstract
  public type.max float.this is abstract
  public type.epsilon float.this is abstract


  # square root
  #
  public type.square_root (val float.this) float.this is 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 is abstract


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


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


  # trigonometric

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


  # hyperbolicus

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


  # area hyperbolicus

  public type.asinh(val float.this) float.this is
    # ln(x+sqrt(x^2+1))
    log (val + sqrt (val ** two + one))
  public type.acosh(val float.this) float.this is
    # ln(x+sqrt(x^2-1))
    log (val + sqrt (val ** two - one))
  public type.atanh(val float.this) float.this is
    # 1/2*ln((1+x)/(1-x))
    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 is
    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 is
    a.infix <= b || is_NaN a