Fuzion Logo
fuzion-lang.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.
#
module:public integer : numeric is

  # division remainder
  public redef infix % (other integer.this) integer.this
    pre
      safety: other != integer.this.zero
  => abstract

  # test divisibility by other
  public infix %% (other integer.this) bool
    pre
      safety: other != integer.this.zero
  =>
    integer.this % other = integer.this.zero

  # bitwise operations
  public infix &  (other integer.this) integer.this => abstract
  public infix |  (other integer.this) integer.this => abstract
  public infix ^  (other integer.this) integer.this => abstract

  # bitwise NOT
  public prefix ~ integer.this
    pre
      is_bounded
  => abstract

  # bitwise NOT (Unicode alias)
  public prefix ¬ integer.this =>
    ~integer.this

  # shift operations
  public infix >> (other integer.this) integer.this
    pre
      safety: other.sign ≥ 0
  => abstract

  public infix << (other integer.this) integer.this
    pre
      safety: other.sign ≥ 0
  => abstract

  # check if this type of integer is bounded
  #
  # returns false unless redefined by a specific implementation of integer
  public is_bounded => false

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


  # create a fraction
  public infix /-/ (other integer.this) => (num.fraction integer.this other).reduce

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


  # convert this to a decimal number in a string.  If negative, add "-" as
  # the first character.
  #
  public redef as_string String => integer.this.as_string 10


  # convert this to a number using the given base.  If negative, add "-" as
  # the first character.
  #
  public as_string(base u32) String : character_encodings
    pre
      debug: 1 < base ≤ 36
  =>
    b := integer.this.from_u32 base

    if integer.this.sign < 0
      # there could be an overflow on negation
      match -? integer.this
        v integer.this => "-" + v.as_string base
        nil => ("-" + (-(integer.this / b)).as_string base) + (-(integer.this % b)).as_string base
    else
      # this digit as an UTF-8 byte
      digit_as_utf8_byte(d u8) u8
      pre d ≤ 35 # 35 would be a Z
      =>
        if d < 10 then String.zero_char + d else String.a_char + d - 10

      as_list0 (power integer.this) =>
        if power.sign <= 0
          nil
        else
          digit := (integer.this / power % b).as_u8
          list (digit_as_utf8_byte digit) (()-> as_list0 power/b)

      String.from_bytes (as_list0 (integer.this.highest b))


  # 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
  #
  public as_string(len i32, base u32) String
    pre
      debug: 1 < base ≤ 36
    post
      debug: result.byte_length ≥ len
  =>
    # create number
    n := integer.this.as_string base

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

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

    # put it all together
    sgn + zeros + digits


  # create binary representation
  #
  public bin => integer.this.as_string 2


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


  # create octal representation
  #
  public oct => integer.this.as_string 8


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


  # create decimal representation
  #
  public dec => integer.this.as_string 10


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


  # create hexadecimal representation
  #
  public hex => integer.this.as_string 16


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


  # the least significant byte of this integer
  module low8bits u8 => abstract