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
last changed: 2024-03-07