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 division remainder operation %, bitwise logical operations,
# shift operations and gcd. Also, integers can be used to build fractions.
#
public integer : numeric is


  # preconditions used in 'numeric' for basic operations: true if the
  # operation is permitted for the given values
  public redef infix /! (other integer.this) bool => other != integer.this.zero
  public redef infix %! (other integer.this) bool => other != integer.this.zero


  # 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
      debug: 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 bool => 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 => (num.fraction integer.this other).reduce

  # create a fraction via unicode fraction slash \u2044 '⁄ '
  public infix ⁄ (other integer.this) num.fraction 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 : encodings
    pre
      debug: 1 < base ≤ 36
  =>
    b := integer.this.from_u32 base

    # this digit as an UTF-8 byte
    digit_as_utf8_byte(d u8) u8
    pre debug: 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)

    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
      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 String => integer.this.as_string 2


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


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


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


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


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


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


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


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

last changed: 2025-07-10