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

f32.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 f32
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# f32 -- 32 bit floating point values
#
#
# f32 are binary32-numbers as defined in the IEEE 754-2019 standard, see
# https://ieeexplore.ieee.org/servlet/opac?punumber=8766227
#
public f32(public val f32) : float is


  # basic operations: 'prefix -' (negation)
  public fixed redef prefix - f32 is intrinsic
  public fixed infix + (other f32) f32 is intrinsic
  public fixed infix - (other f32) f32 is intrinsic
  public fixed infix * (other f32) f32 is intrinsic
  public fixed infix / (other f32) f32 is intrinsic
  public fixed infix % (other f32) f32 is intrinsic
  public fixed infix ** (other f32) f32 is intrinsic


  # comparision
  #
  fixed infix = (other f32) bool is intrinsic_constructor
  fixed infix <= (other f32) bool is intrinsic_constructor
  fixed infix >= (other f32) bool is intrinsic_constructor
  fixed infix < (other f32) bool is intrinsic_constructor
  fixed infix > (other f32) bool is intrinsic_constructor


  # conversion
  redef as_i64 => as_f64.as_i64


  public as_f64 f64 is intrinsic


  # casting bit representation to u32
  public cast_to_u32 u32 is intrinsic


  # create hash code from this number
  #
  # special handling for floats:
  # although -0.0 and 0.0 are different in bit representation,
  # they are considered equal by both type.equality and IEEE
  # standard, hence they should have the same hash.
  # all NaNs are considered equal by type.equality (but not
  # the IEEE standard), so the hash of any NaN is the hash of
  # the "canonical" NaN.
  #
  public type.hash_code(a f32.this) u64 is
    if is_NaN a.val
      hash NaN.cast_to_u32
    else if a = zero
      hash zero.cast_to_u32
    else
      hash a.cast_to_u32



  # is the sign bit set?
  public is_sign_bit_set bool is
    cast_to_u32 >= 1P31


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


  # number of bits used for exponent
  #
  public type.exponent_bits => 8


  # mask for the the bits that encode the mantissa
  public type.mantissa_mask => u32 1P23 - 1


  # mask for the the bits that encode the exponent
  # (the mask is not shifted to the correct position)
  public type.exponent_mask => u32 1P8 - 1


  # the exponent bias (the zero offset of the exponent)
  public type.exponent_bias => 127


  # the biased exponent
  public exponent_biased => ((cast_to_u32 >> f32.type.mantissa_bits.as_u32) & f32.type.exponent_mask).as_i32


  # the normalized exponent
  public exponent =>
    if exponent_biased = 0
      1 - f32.type.exponent_bias
    else
      exponent_biased - f32.type.exponent_bias


  # the normalized mantissa
  public mantissa =>
    m := cast_to_u32 & f32.type.mantissa_mask
    if exponent_biased = 0
      m.as_u64
    else
      ((u32 1 << f32.type.mantissa_bits.as_u32) | m).as_u64



  # the fraction of the floating point number
  public fixed redef fract f32 is
    if f32.type.is_NaN val
      f32.type.NaN
    else if val < (f32 0)
      -(-val).fract
    else if val < (f32 1)
      val
    else
      shift := (f32.type.mantissa_bits - exponent)
      if (shift > 0)
        whole := cast_to_u32 & (u32.type.max << shift.as_u32)
        val - whole.cast_to_f32
      else
        0.0


  # true when the absolute value
  # is smaller than 0.001
  # or greater than 9_999_999
  #
  public use_scientific_notation bool is
    abs<1E-3 || abs>=1E7


  # convert this to a string.
  #
  public redef as_string =>
    (num.ryū f32).as_string val


  # -----------------------------------------------------------------------
  #
  # type features:


  # identity element for 'infix +'
  #
  public fixed type.zero f32 is 0


  # identity element for 'infix *'
  #
  public fixed type.one  f32 is 1


  public fixed type.bytes => 4


  public fixed type.ℇ => f32 2.7182818284590452354


  public fixed type.π => f32 3.14159265358979323846


  public fixed type.from_i64(val i64) f32 is
    val.as_f32


  public fixed type.is_NaN(val f32) bool is intrinsic_constructor


  public fixed type.min_exp i32 is intrinsic
  public fixed type.max_exp i32 is intrinsic
  public fixed type.min_positive f32 is intrinsic
  public fixed type.max f32 is intrinsic
  public fixed type.epsilon f32 is intrinsic


  public fixed type.square_root(val f32) f32 is intrinsic

  public fixed type.exp(val f32) f32 is intrinsic
  public fixed type.log(val f32) f32 is intrinsic


  public fixed type.sin(val f32) f32 is intrinsic
  public fixed type.cos(val f32) f32 is intrinsic
  public fixed type.tan(val f32) f32 is intrinsic
  public fixed type.asin(val f32) f32 is intrinsic
  public fixed type.acos(val f32) f32 is intrinsic
  public fixed type.atan(val f32) f32 is intrinsic

  # atan(y/x) with a few special cases
  # see also: https://go.dev/src/math/atan2.go
  #
  public fixed type.atan2(y, x f32) f32 is
    if is_NaN y || is_NaN x
      NaN
    if y = 0
      if x > 0 || (x = 0 && x.is_sign_bit_set)
        y
      else
        if y.is_sign_bit_set then -π else π
    else if x = 0
      if y > 0 then π/2 else -π/2
    else if x = f32.type.positive_infinity
      if y = f32.type.positive_infinity
        π/4
      else if y = f32.type.negative_infinity
        -π/4
      else
        0
    else if x = f32.type.negative_infinity
      if y = f32.type.positive_infinity
        (f32 3.0)*π/4
      else if y = f32.type.negative_infinity
        -(f32 3.0)*π/4
      else if y > 0
        π
      else // y < 0
        -π
    else if y = f32.type.positive_infinity
      π/2
    else if y = f32.type.negative_infinity
      -π/2
    else
      q := atan y/x
      if x < 0
        if q <= 0 then q+π else q-π
      else
        q


  public fixed type.sinh (val f32) f32 is intrinsic
  public fixed type.cosh (val f32) f32 is intrinsic
  public fixed type.tanh (val f32) f32 is intrinsic