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

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

# fraction
#
#
# fraction provides fraction numbers based on an integer type to represent the
# numerator and the denominator.
#
# basic numeric operations +, -, * and comparison are supported. numerator and
# denominator are reduced after each operation.
#
# there are currently no checks or preconditions for overflows in the numerator
# or the denominator.
#
fraction(B (integer B).type,
         num,    # numerator
         den B   # denominatior
        ) : numeric (fraction B)
  pre
    safety: den.sign > 0 # denominator must be positive
is

# private:

  # just for brevity
  a => fraction num den

# public:

  # enable generic features in ancestors
  redef thiz => a

  # reduce numerator and denominator by their gcd:
  reduce =>
    gcd := num.abs.gcd(den)
    if gcd == num.one
      a
    else
      fraction(num / gcd,
               den / gcd)

  redef zero => fraction(num.zero, num.one)
  redef one  => fraction(num.zero, num.one)

  # basic operations
  redef prefix + => a
  redef prefix - => fraction -a.num a.den
  redef infix +  (b fraction B) => fraction(num * b.den + b.num * den, den * b.den).reduce
  redef infix -  (b fraction B) => fraction(num * b.den - b.num * den, den * b.den).reduce
  redef infix *  (b fraction B) => fraction(num * b.num              , den * b.den).reduce
  redef infix /  (b fraction B) fraction B
    pre
      safety: b != zero
  is fraction(num * b.den                  , den * b.num).reduce

  # comparison
  redef infix == (b fraction B) =>  (a - b).num.isZero
  redef infix != (b fraction B) => !(a - b).num.isZero
  redef infix <  (b fraction B) =>  (a - b).num.sign <  0
  redef infix <= (b fraction B) =>  (a - b).num.sign <= 0
  redef infix >  (b fraction B) =>  (a - b).num.sign >  0
  redef infix >= (b fraction B) =>  (a - b).num.sign >= 0

  redef asString => "" + num + "⁄" + den