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

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

# numeric -- parent of all numeric features
#
public numeric : property.hashable, property.orderable is

  public is_zero bool => numeric.this = numeric.this.zero
  public is_one  bool => numeric.this = numeric.this.one

  # basic operations: 'prefix +' (identity)
  public prefix + numeric.this
    pre
      debug: +!numeric.this
  => numeric.this

  # basic operations: 'prefix -' (negation)
  public prefix - numeric.this
    pre
      debug: -!numeric.this
  => numeric.this.zero - numeric.this

  # basic operations: 'infix +' (addition)
  public infix +  (other numeric.this) numeric.this
    pre
      debug: (numeric.this +! other)
  => abstract

  # basic operations: 'infix -' (subtraction)
  public infix -  (other numeric.this) numeric.this
    pre
      debug: (numeric.this -! other)
  => abstract

  # basic operations: 'infix *' (multiplication)
  public infix *  (other numeric.this) numeric.this
    pre
      debug: (numeric.this *! other)
  => abstract

  # basic operations: 'infix /' (division)
  public infix /  (other numeric.this) numeric.this
    pre
      debug: (numeric.this /! other)
  => abstract

  # basic operations: 'infix %' (division remainder)
  public infix %  (other numeric.this) numeric.this
    pre
      debug: (numeric.this %! other)
  => abstract

  # basic operations: 'infix **' (exponentiation)
  public infix ** (other numeric.this) numeric.this
    pre
      debug: (numeric.this **! other)
  => abstract


  # preconditions for basic operations: true if the operation's result is
  # representable and defined for the given values
  #
  # default implementations all return `true` such that children have to
  # redefine these only for partial operations such as those resulting in
  # an overflow or that are undefined like a division by zero for most
  # types.
  #
  public prefix +! bool => true
  public prefix -! bool => true
  public infix +! (other numeric.this) bool => true
  public infix -! (other numeric.this) bool => true
  public infix *! (other numeric.this) bool => true
  public infix /! (other numeric.this) bool => true
  public infix %! (other numeric.this) bool => true
  public infix **!(other numeric.this) bool => true


  # overflow checking operations
  public prefix -? option numeric.this => - numeric.this
  public infix +? (other numeric.this) option numeric.this => numeric.this + other
  public infix -? (other numeric.this) option numeric.this => numeric.this - other
  public infix *? (other numeric.this) option numeric.this => numeric.this * other
  public infix **?(other numeric.this) option numeric.this
    pre
      debug: (other ≥ numeric.this.zero)
  => abstract

  # saturating  operations
  public prefix -^  numeric.this => - numeric.this
  public infix +^ (other numeric.this) numeric.this => numeric.this + other
  public infix -^ (other numeric.this) numeric.this => numeric.this - other
  public infix *^ (other numeric.this) numeric.this => numeric.this * other
  public infix **^(other numeric.this) numeric.this
    pre
      debug: (other ≥ numeric.this.zero)
  => abstract


  # sign function resulting in `-1`/`0`/`+1` depending on whether `numeric.this`
  # is less than, equal or greater than zero
  #
  public sign i32 =>
    if      numeric.this = numeric.this.zero then  0
    else if numeric.this > numeric.this.zero then  1
    else                                          -1


  # absolute value
  #
  public abs numeric.this =>
    if sign ≥ 0 then  numeric.this
    else             -numeric.this


  # absolute value using `|a|` built from a `prefix |` and `postfix |` as an operator
  # alias of `a.abs`
  #
  # Due to the low precedence of `|`, this works also on expressions like `|a-b|`, even
  # with spaces `| a-b |`, `|a - b|`, `| a-b|` or `|a-b |`.
  #
  # Nesting, however, does not work, e.g, `| - |a| |`, this requires parentheses `|(- |a|)|`.
  #
  public prefix | is

    # only useful operation is the corresponding `prefix |`
    #
    public postfix | numeric.this => numeric.this.abs

    # redefine as_string to try to explain what is wrong if only one `|` is used
    #
    public redef as_string String =>
      "*** numeric.postfix |, requires corresponding prefix | for abs value ***"


  # does this numeric value fit into an u8? This is redefined by children
  # of numeric that support `as_u8`.
  #
  public fits_in_u8 bool => false


  # this numeric value as an u8
  public as_u8 u8
    pre
      debug: fits_in_u8
  => abstract


  # find the highest power of b that is less or equal than numeric.this.
  #
  module highest(b numeric.this) numeric.this
    pre
      debug: (numeric.this.sign ≥ 0)
    post
      debug: (numeric.this = numeric.this.zero: result = numeric.this.one)
      debug: (numeric.this != numeric.this.zero: numeric.this / b < result ≤ numeric.this)
  # NYI: original postcondition code should cause a compiler error since
  # result.infix <= expects an argument of type T while integer.this =>
  # not of type T.
  #
  #     integer.this != zero: integer.this / b < result <= integer.this
  =>
    for
      bs := numeric.this.one, bs * b
    while numeric.this / b ≥ bs


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


  # identity element for 'infix +'
  #
  public type.zero numeric.this => abstract


  # identity element for 'infix *'
  #
  public type.one  numeric.this => abstract


  # the value corresponding to v in whatever integer implementation we have,
  # maximum in case of overflow
  #
  public type.from_u32(v u32) numeric.this =>
    if v = 0 zero else (from_u32 v-1) +^ one


  # the constant '2' in whatever integer implementation we have, maximum in case of overflow
  #
  public type.two numeric.this => from_u32 2


  # the constant '10' in whatever integer implementation we have, maximum in case of overflow
  #
  public type.ten numeric.this => from_u32 10


  # monoid of numeric with infix + operation.  Will create sum of all elements it
  # is applied to.
  #
  public type.sum Monoid numeric.this =>
    ref : Monoid numeric.this is
      public redef infix ∙ (a, b numeric.this) numeric.this => a + b
      public redef e numeric.this => zero


  # monoid of numeric with infix * operation.  Will create product of all elements
  # it is applied to.
  #
  public type.product Monoid numeric.this =>
    ref : Monoid numeric.this is
      public redef infix ∙ (a, b numeric.this) numeric.this => a * b
      public redef e numeric.this => one


  # monoid of numeric with infix +^ operation.  Will create sum of all elements it
  # is applied to, stopping at max/min value in case of overflow.
  #
  public type.sum_saturating Monoid (numeric.this) =>
    ref : Monoid numeric.this is
      public redef infix ∙ (a, b numeric.this) numeric.this => a +^ b
      public redef e numeric.this => zero


  # monoid of numeric with infix *^ operation.  Will create product of all elements
  # it is applied to, stopping at max/min value in case of overflow.
  #
  public type.product_saturating Monoid (numeric.this) =>
    ref : Monoid numeric.this is
      public redef infix ∙ (a, b numeric.this) numeric.this => a *^ b
      public redef e numeric.this => one

last changed: 2025-06-17