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 => intrinsic
public fixed infix + (other f32) f32 => intrinsic
public fixed infix - (other f32) f32 => intrinsic
public fixed infix * (other f32) f32 => intrinsic
public fixed infix / (other f32) f32 => intrinsic
public fixed infix % (other f32) f32 => intrinsic
public fixed infix ** (other f32) f32 => intrinsic
# comparision
#
fixed infix = (other f32) bool => intrinsic_constructor
fixed infix <= (other f32) bool => intrinsic_constructor
fixed infix >= (other f32) bool => intrinsic_constructor
fixed infix < (other f32) bool => intrinsic_constructor
fixed infix > (other f32) bool => intrinsic_constructor
# conversion
redef as_i64 => as_f64.as_i64
public as_f64 f64 => intrinsic
# casting bit representation to u32
public cast_to_u32 u32 => 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 =>
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 =>
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.mantissa_bits.as_u32) & f32.exponent_mask).as_i32
# the normalized exponent
public exponent =>
if exponent_biased = 0
1 - f32.exponent_bias
else
exponent_biased - f32.exponent_bias
# the normalized mantissa
public mantissa =>
m := cast_to_u32 & f32.mantissa_mask
if exponent_biased = 0
m.as_u64
else
((u32 1 << f32.mantissa_bits.as_u32) | m).as_u64
# the fraction of the floating point number
public fixed redef fract f32 =>
if f32.is_NaN val
f32.NaN
else if val < (f32 0)
-(-val).fract
else if val < (f32 1)
val
else
shift := (f32.mantissa_bits - exponent)
if (shift > 0)
whole := cast_to_u32 & (u32.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 =>
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 => 0
# identity element for 'infix *'
#
public fixed type.one f32 => 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 =>
val.as_f32
public fixed type.is_NaN(val f32) bool => intrinsic_constructor
public fixed type.min_exp i32 => intrinsic
public fixed type.max_exp i32 => intrinsic
public fixed type.min_positive f32 => intrinsic
public fixed type.max f32 => intrinsic
public fixed type.epsilon f32 => intrinsic
public fixed type.square_root(val f32) f32 => intrinsic
public fixed type.exp(val f32) f32 => intrinsic
public fixed type.log(val f32) f32 => intrinsic
public fixed type.sin(val f32) f32 => intrinsic
public fixed type.cos(val f32) f32 => intrinsic
public fixed type.tan(val f32) f32 => intrinsic
public fixed type.asin(val f32) f32 => intrinsic
public fixed type.acos(val f32) f32 => intrinsic
public fixed type.atan(val f32) f32 => 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 =>
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.positive_infinity
if y = f32.positive_infinity
π/4
else if y = f32.negative_infinity
-π/4
else
0
else if x = f32.negative_infinity
if y = f32.positive_infinity
(f32 3.0)*π/4
else if y = f32.negative_infinity
-(f32 3.0)*π/4
else if y > 0
π
else // y < 0
-π
else if y = f32.positive_infinity
π/2
else if y = f32.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 => intrinsic
public fixed type.cosh (val f32) f32 => intrinsic
public fixed type.tanh (val f32) f32 => intrinsic
last changed: 2024-03-07