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

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

# integer -- abstract ancestor of integer numbers
#
# integer is the abstract ancestor of integer numbers that provides operations
# from numeric plus a devision remainder operation %, bitwise logical operations,
# shift operations and gcd. Also, integers can be used to build fractions.
#
integer(I (integer I).type) : numeric I is

  # division remainder
  redef infix % (other I) I
    pre
      safety: other != zero
  is abstract

  # test divisibility by other
  infix %% (other I) bool
    pre
      safety: other != zero
  is
    thiz % other == zero

  # bitwise operations
  infix &  (other I) I is abstract
  infix |  (other I) I is abstract
  infix ^  (other I) I is abstract

  # shift operations
  infix >> (other I) I
    pre
      safety: other.sign >= 0
  is abstract

  infix << (other I) I
    pre
      safety: other.sign >= 0
  is abstract

  # greatest common divisor of this and b
  #
  # note that this assumes zero to be divisible by any positive integer.
  gcd(b I) I
    pre
      safety: sign >= 0,
      safety: b.sign >= 0
  is
    if b == zero
      thiz
    else
      b.gcd(thiz % b)  # tail recursion

  # create a fraction
  infix /-/ (other I) => (fraction thiz other).reduce

  # create a fraction via unicode fraction slash \u2044 '⁄ '
  infix ⁄ (other I) => integer.this /-/ other


  # convert this to a decimal number in a string.  If negative, add "-" as
  # the first character.
  #
  redef asString string is integer.this.asString 10


  # convert this to a number using the given base.  If negative, add "-" as
  # the first character.
  #
  asString(base u32) string : character_encodings
    pre
      debug: u32 1 < base <= 36
  is
    ref : string
      redef utf8 ref : Sequence u8 is
        redef asStream stream u8 is
          b := from_u32 base
          if thiz.sign >= 0
            ref : stream u8
              p := thiz.highest b
              redef hasNext => p.sign > 0
              redef next =>
                d := (thiz / p % b).to_u32.as_u8
                r := if (d < 10) strings.zeroChar + d else strings.aChar + (d - ascii.lf)
                set p := p / b
                r
          else
            p := -? thiz
            match p
              v I   => ("-" + v .asString base).utf8.asStream
              _ nil => (("-" + (-(thiz / b)).asString base) + (-(thiz % b)).asString base).utf8.asStream


  # convert this to a number using the given base.  If negative, add "-" as
  # the first character.  Extend with leading "0" until the length is at
  # least len
  #
  asString(len i32, base u32) string
    pre
      debug: u32 1 < base <= 36
    post
      debug: result.byteLength >= len
  is
    # create number
    n := integer.this.asString base

    # split n into sign and digits
    (sign, digits) := if (integer.this.sign < 0) ("-", strings.fromBytes (n.utf8.drop 1)) else ("", n)

    # create required additional zeros
    zeros := "0" * 0.max (len - n.byteLength)

    # put it all together
    sign + zeros + digits


  # create binary representation
  #
  bin => integer.this.asString 2


  # create binary representation with given number of digits.
  #
  bin(len i32) => integer.this.asString len 2


  # create octal representation
  #
  oct => integer.this.asString 8


  # create octal representation with given number of digits.
  #
  oct(len i32) => integer.this.asString len 8


  # create decimal representation
  #
  dec => integer.this.asString 10


  # create decimal representation with given number of digits.
  #
  dec(len i32) => integer.this.asString len 10


  # create hexadecimal representation
  #
  hex => integer.this.asString 16


  # create hexadecimal representation with given number of digits.
  #
  hex(len i32) => integer.this.asString len 16