Fuzion Logo
flang.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
#
numeric(redef T (numeric T).type) : hasHash T, ordered T, numerics T is

  # get numeric.this value of type T.  This is used for a generic implemention
  # of some features (e.g. prefix -, abs
  thiz T is abstract

  isZero => numeric.this == zero
  isOne  => numeric.this == one

  # basic operations: 'prefix +' (identity)
  prefix + T
    pre
      safety: +!thiz
  is thiz

  # basic operations: 'prefix -' (negation)
  prefix - T
    pre
      safety: -!thiz
  is zero - thiz

  # basic operations: 'infix +' (addition)
  infix +  (other T) T
    pre
      safety: thiz +! other
  is abstract

  # basic operations: 'infix -' (substraction)
  infix -  (other T) T
    pre
      safety: thiz -! other
  is abstract

  # basic operations: 'infix *' (multiplication)
  infix *  (other T) T
    pre
      safety: thiz *! other
  is abstract

  # basic operations: 'infix /' (division)
  infix /  (other T) T
    pre
      safety: thiz /! other,
      safety: other != zero
  is abstract

  # basic operations: 'infix %' (division remainder)
  infix %  (other T) T
    pre
      safety: thiz %! other,
      safety: other != zero
  is abstract

  # basic operations: 'infix **' (exponentiation)
  infix ** (other T) T
    pre
      safety: thiz **! other,
      safety: other >= zero
  is abstract


  # preconditions for basic operations: true if the operation's result is
  # representable for the given values
  #
  # This does not check if the operation is defined (i.e, it
  # returns true for '3/!0' or '0**!0'.
  #
  prefix +! bool is true
  prefix -! bool is abstract
  infix +! (other T) bool is abstract
  infix -! (other T) bool is abstract
  infix *! (other T) bool is abstract
  infix /! (other T) bool is abstract
  infix %! (other T) bool is abstract
  infix **!(other T) bool is abstract


  # overflow checking operations
  prefix -? numOption T is - thiz
  infix +? (other T) numOption T is thiz + other
  infix -? (other T) numOption T is thiz - other
  infix *? (other T) numOption T is thiz * other
  infix **?(other T) numOption T is abstract

  # saturating  operations
  prefix -^  T is - thiz
  infix +^ (other T) T is thiz + other
  infix -^ (other T) T is thiz - other
  infix *^ (other T) T is thiz * other
  infix **^(other T) T is abstract

  # comparison
  infix == (other T) bool is abstract   // NYI: remove, replace by 'infix ='
  redef infix = (other T) bool is thiz == other
  infix != (other T) bool is   // NYI: remove, replace by 'infix /='
    !(thiz == other)

  sign => if numeric.this == zero then 0 else if numeric.this > zero then 1 else -1

  abs => if sign >= 0 then thiz else -thiz

  # minimum of numeric.this and other
  #
  min(other T) T is if (numeric.this <= other) thiz else other

  # maximum of numeric.this and other
  #
  max(other T) T is if (numeric.this >= other) thiz else other


  # the u32 value corresponding to this
  # note: potential fraction will be discarded
  to_u32 u32
    pre
      debug: thiz >= zero
  is
    if (thiz >= one) ((thiz - one).to_u32 + 1)
    else 0


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


  # is this part of given set
  #
  # NYI: infix operators currently always use dynamic binding on the lhs and pass
  # the rhs as an argument.  If we would support an 'rinfix ∈' that would use the
  # rhs for dynamic binding and the lhs as argument, we could define '∈' in Set T
  # and it would work for all set types.
  #
  elementOf(s Set T) => s.contains thiz
  infix ∈ (s Set T) => numeric.this.elementOf s


  # is this not part of given set
  #
  notElementOf(s Set T) => !elementOf s
  infix ∉ (s Set T) => numeric.this.notElementOf s


# numerics -- unit type defining features related to numeric but not
# requiring an instance
#
numerics(T (numeric T).type) is

  # name of this numeric type, e.g., "u64"
  #
  name string is abstract

  # identity element for 'infix +'
  #
  zero T is abstract

  # identity element for 'infix *'
  #
  one  T is abstract

  # the constant '2' in whatever integer implementation we have, maximum in case of overflow
  two => from_u32(2)

  # the constant '10' in whatever integer implementation we have, maximum in case of overflow
  ten => from_u32(10)

  # the value corresponding to v in whatever integer implementation we have, maximum in case of overflow
  from_u32(v u32) T is
    if v == 0 zero else from_u32(v-1) +^ one

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

  # monoid of numeric with infix * operation.  Will create product of all elements
  # it is applied to.
  #
  product : Monoid T is
    redef infix ∙ (a, b T) T is a * b
    redef infix == (a, b T) bool is a == b
    redef e T is 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.
  #
  sumSaturating : Monoid T is
    redef infix ∙ (a, b T) T is a +^ b
    redef infix == (a, b T) bool is a == b
    redef e T is 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.
  #
  productSaturating : Monoid T is
    redef infix ∙ (a, b T) T is a *^ b
    redef infix == (a, b T) bool is a == b
    redef e T is one