num/wrap_around.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 wrap_around
#
# Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------
# wrap_around -- abstract ancestor of wrap-around integer numbers
#
# wrap_around is the abstract ancestor of integer numbers that have min and
# max values and operations with wrap-around semantics.
#
module:public wrap_around : integer is
# overflow checking
# would negation -wrap_around.this cause an overflow?
public wrapped_on_neg bool => abstract
# would addition wrap_around.this + other cause an overflow or underflow?
public overflow_on_add(other wrap_around.this) bool => abstract
public underflow_on_add(other wrap_around.this) bool => abstract
public wrapped_on_add(other wrap_around.this) => overflow_on_add other || underflow_on_add other
# would subtraction wrap_around.this - other cause an overflow or underflow?
public overflow_on_sub(other wrap_around.this) bool => abstract
public underflow_on_sub(other wrap_around.this) bool => abstract
public wrapped_on_sub(other wrap_around.this) => overflow_on_sub other || underflow_on_sub other
# would multiplication wrap_around.this * other cause an overflow or underflow?
public overflow_on_mul(other wrap_around.this) bool => abstract
public underflow_on_mul(other wrap_around.this) bool => abstract
public wrapped_on_mul(other wrap_around.this) => overflow_on_mul other || underflow_on_mul other
# preconditions used in 'numeric' for basic operations: true if the
# operation is permitted for the given values
public prefix -! => !wrapped_on_neg
public infix +! (other wrap_around.this) => !(overflow_on_add other) && !(underflow_on_add other)
public infix -! (other wrap_around.this) => !(overflow_on_sub other) && !(underflow_on_sub other)
public infix *! (other wrap_around.this) => !(overflow_on_mul other) && !(underflow_on_mul other)
public infix /! (other wrap_around.this) => true # other != zero is checked in separate condition
public infix %! (other wrap_around.this) => true # other != zero is checked in separate condition
public infix **!(other wrap_around.this) => !(overflow_on_exp other)
# neg, add, sub, mul with wrap-around semantics
public prefix -° wrap_around.this => abstract
public infix +° (other wrap_around.this) wrap_around.this => abstract
public infix -° (other wrap_around.this) wrap_around.this => abstract
public infix *° (other wrap_around.this) wrap_around.this => abstract
public is_min => wrap_around.this = wrap_around.this.min
public is_max => wrap_around.this = wrap_around.this.max
# check if this type of wrap_around is bounded
#
# wrap_arounds are assumed to be a bound set by default, so
# this returns true unless redefined by an implementation
public redef is_bounded => true
# basic operations with runtime error on overflow
# negation, with check for overflow
public redef prefix - wrap_around.this
pre
debug: !wrapped_on_neg
=> -° wrap_around.this
# addition, with check for overflow
public redef infix + (other wrap_around.this) wrap_around.this
pre
debug: !(overflow_on_add other)
debug: !(underflow_on_add other)
=> wrap_around.this +° other
# subtraction, with check for overflow
public redef infix - (other wrap_around.this) wrap_around.this
pre
debug: !(overflow_on_sub other)
debug: !(underflow_on_sub other)
=> wrap_around.this -° other
# multiplication, with check for overflow
public redef infix * (other wrap_around.this) wrap_around.this
pre
debug: !(overflow_on_mul other)
debug: !(underflow_on_mul other)
=> wrap_around.this *° other
# overflow checking operations
public redef prefix -? num_option wrap_around.this => if wrapped_on_neg then nil else -wrap_around.this
public redef infix +? (other wrap_around.this) num_option wrap_around.this => if wrapped_on_add other then nil else wrap_around.this + other
public redef infix -? (other wrap_around.this) num_option wrap_around.this => if wrapped_on_sub other then nil else wrap_around.this - other
public redef infix *? (other wrap_around.this) num_option wrap_around.this => if wrapped_on_mul other then nil else wrap_around.this * other
# saturating operations
public redef prefix -^ => if wrapped_on_neg if wrap_around.this > wrap_around.this.zero then wrap_around.this.min else wrap_around.this.max else - wrap_around.this
public redef infix +^ (other wrap_around.this) => if overflow_on_add other then wrap_around.this.max else if underflow_on_add other then wrap_around.this.min else wrap_around.this + other
public redef infix -^ (other wrap_around.this) => if overflow_on_sub other then wrap_around.this.max else if underflow_on_sub other then wrap_around.this.min else wrap_around.this - other
public redef infix *^ (other wrap_around.this) => if overflow_on_mul other then wrap_around.this.max else if underflow_on_mul other then wrap_around.this.min else wrap_around.this * other
# exponentiation for positive exponent
#
# 'zero ** zero' is permitted and results in 'one'.
#
public infix ** (other wrap_around.this) wrap_around.this
pre
safety: (other ≥ wrap_around.this.zero)
debug: (!overflow_on_exp other)
=>
wrap_around.this **° other
# exponentiation with wrap-around semantics
#
# 'zero **° zero' is permitted and results in 'one'.
#
public infix **° (other wrap_around.this) wrap_around.this
pre
safety: (other ≥ wrap_around.this.zero)
=>
if (other = wrap_around.this.zero) wrap_around.this.one
else if (other = wrap_around.this.one ) wrap_around.this
else
tmp := (wrap_around.this *° wrap_around.this) **° (other / wrap_around.this.two)
if other %% wrap_around.this.two
tmp
else
tmp *° wrap_around.this
# exponentiation with overflow checking semantics
#
# 'zero **? zero' is permitted and results in 'one'.
#
public infix **? (other wrap_around.this) num_option wrap_around.this
pre
safety: (other ≥ wrap_around.this.zero)
=>
if (other = wrap_around.this.zero) wrap_around.this.one
else if (other = wrap_around.this.one ) wrap_around.this
else
tmp := (wrap_around.this *? wrap_around.this) **? (other / wrap_around.this.two)
if other %% wrap_around.this.two
tmp
else
tmp *? wrap_around.this
# would exponentiation 'this ** other' cause an overflow?
#
public overflow_on_exp(other wrap_around.this) => (wrap_around.this **? other)!!
# exponentiation with saturating semantics
#
# 'zero **^ zero' is permitted and results in 'one'.
#
public infix **^ (other wrap_around.this) wrap_around.this
pre
safety: (other ≥ wrap_around.this.zero)
=>
if overflow_on_exp other
if (wrap_around.this ≥ wrap_around.this.zero) || (other %% wrap_around.this.two)
wrap_around.this.max
else
wrap_around.this.min
else
wrap_around.this ** other
# bitwise NOT
public redef prefix ~ wrap_around.this
pre
is_bounded
=>
wrap_around.this ^ wrap_around.this.all_bits_set
# count the number of 1 bits in the binary representation of this
# integer.
#
public ones_count i32 => abstract
# this integer as an array of bytes (little endian)
public as_bytes array u8 =>
bs := wrap_around.this.byte_size
array u8 bs (idx ->
shift wrap_around.this := wrap_around.this.from_u32 (bs.as_u32-idx.as_u32-1)*8
(wrap_around.this>>shift).low8bits)
# returns the number in whose bit representation all bits are ones
public type.all_bits_set wrap_around.this => abstract
# how many bytes does this integer use?
public type.byte_size i32 =>
# NYI #1179
all_bits_set.ones_count / 8
# minimum
#
public type.min wrap_around.this => abstract
# maximum
#
public type.max wrap_around.this => abstract
last changed: 2024-03-07