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

int.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 int
#
#  Author: Michael Lill (michael.lill@tokiwa.software)
#
# -----------------------------------------------------------------------

# int -- signed integer values of arbitrary size
#
module:public int (is_positive bool, n uint) : has_interval
is

  # normalize the sign => no minus zero
  ns := if n = uint.zero then true else is_positive

  # the actually relevant data of this uint.
  # irrelevant zeros at start are dropped.
  # zero is represented by the empty list.
  data := n.b.drop_while (=0)

  name String =>
    "int"

  public fixed redef type.zero int =>
    int true uint.zero

  public fixed redef type.one int =>
    int true uint.one


  public fixed redef prefix - int =>
    int !ns n


  # add this int to other
  public fixed redef infix +  (other int) int =>
    if ns = other.ns
      int ns n+other.n
    else
      if ns
        int.this - (-other)
      else
        other - (-int.this)


  # subtract other from this int
  public fixed redef infix - (other int) int =>
    if other.ns

      if ns
        if n ≥ other.n
          int true (n - other.n)
        else
          int false (other.n - n)
      else
        -(-int.this + other)

    # minus, minus => plus
    else
      int.this + -other


  # the sign of the result of the
  # multiplication or division of int.this and other
  result_sign_mul_div(other int) =>
    ns = other.ns


  # multiply this int by other
  public fixed redef infix *  (other int) int =>
    int (result_sign_mul_div other) n*other.n


  # divide this int by other
  public fixed redef infix /  (other int) int
  =>
    s := result_sign_mul_div other
    int (infix /).this.s n/other.n


  # modulo, returns the remainder of the
  # division of this int by other
  public fixed redef infix %  (other int) int =>
    int ns n%other.n


  # exponentation operator:
  # this int to the power of other
  public fixed redef infix ** (other int) int
  =>
    if is_positive
      int true (n ** other.n)
    else
      int (other %% (int 2)) (n ** other.n)


  public fixed redef infix **!(other int) bool =>
    other ≥ int.zero  # 0 and 1 ** -other would be okay but we disallow nonetheless

  public fixed redef infix **?(other int) option int =>
    if other.ns
      int.this ** other
    else
      nil # 0 and 1 ** -other would be okay but we disallow nonetheless

  public fixed redef infix **^(other int) int =>
    if other.ns
      int.this ** other
    else
      panic "negativ exponent is not allowed." # 0 or 1 ** -other would be okay but we disallow nonetheless

  # equality: are these two ints equal?
  #
  public fixed redef type.equality(a, b int) bool =>
    (a.ns = b.ns) & (a.n = b.n)

  # total order
  #
  public fixed redef type.lteq(a, b int) bool =>
    if a.ns
      b.ns && a.n ≤ b.n
    else
      b.ns || b.n ≤ a.n

  public redef as_string String =>
    (if ns then "" else "-") + n.as_string


  # this int as an i32
  public as_i32 i32 =>
    n.as_i32


  # this int as an i64
  public as_i64 i64 =>
    n.as_i64


  # does this numeric value fit into an u8? This is redefined by children
  # of numeric that support `as_u8`.
  #
  public fixed redef fits_in_u8 bool =>
    int.zero ≤ int.this ≤ u8.max.as_int


  # this int as an u8
  public redef as_u8 u8
  =>
      n.as_u8


  # this int as an u32
  public fixed as_u32 u32
  pre debug: int.this >= int.zero
  =>
      n.as_u32


  # this int as an u64
  public fixed as_u64 u64
  pre debug: int.this >= int.zero
  =>
    n.as_u64


  # does this int fit into an u128?
  public fits_in_u128 bool =>
    ns && data.count ≤ 4


  # this int as an u128
  public as_u128 u128
  pre debug: fits_in_u128
  =>
    n.as_u128


  # does this int fit into an i128?
  public fits_in_i128 bool =>
    data.count < 4 | (data.count = 4 && ((data[0] & i32.min.cast_to_u32) = u32 0))


  # this int as an i128
  public as_i128 i128
  pre debug: fits_in_i128
  =>
    if ns
      n.as_i128
    else if data.as_equatable = [u32 0x8000_0000, 0, 0, 0].as_equatable
      i128.min
    else
      -n.as_i128


  # this int as an uint
  public fixed as_uint uint
  pre debug: int.this >= int.zero
  =>
    n


  # helper feature to init int via an i64
  type.from_i64(val i64) int =>
    n u64 := if val = i64.min
               i64.max.as_u64 + 1
             else if val < 0
               (-val).as_u64
             else val.as_u64
    int val>=0 (uint n)


  # helper feature to init int via an i128
  public type.from_i128(val i128) int =>
    s := val >= i128.zero
    if val.is_min
      int s (uint [(u32 0x8000_0000), 0, 0, 0] unit)
    else
      a_val := val.abs
      u_hi := a_val.hi.cast_to_u64
      x0 := (u_hi >> 32).as_u32
      x1 := ((u_hi<<32)>>32).as_u32
      x2 := (a_val.abs.lo >> 32).as_u32
      x3 := ((a_val.abs.lo<<32)>>32).as_u32
      int s (uint [x0, x1, x2, x3] unit)


  # helper feature to init int via a u64
  public type.from_u64(val u64) int =>
    int true (uint val)


  # helper feature to init int via an i32
  public type.from_i32(val i32) int =>
    from_i64 val.as_i64



# shorthand to create an int via an i64
public int (val i64) int =>
  int.from_i64 val

last changed: 2025-06-17