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
last changed: 2024-03-07