Fix power to result type, add tests, adjust docs

This commit is contained in:
Mikko Ahlroth 2024-02-18 20:13:50 +02:00
parent 725f4b7289
commit 331f20e03a
35 changed files with 1734 additions and 447 deletions

4
CHANGELOG.txt Normal file
View file

@ -0,0 +1,4 @@
1.0.0
-----
* Initial release.

View file

@ -41,7 +41,7 @@ latter will return an unranged big integer. An example with `ranged_int/builtin/
where these functions are wrapped:
```gleam
let assert Ok(a) = uint8.from_bigint(bigi.from_int(120))
let assert Ok(a) = uint8.from_int(120)
let b = bigi.from_int(160)
uint8.overflow(uint8.add(a, b)) // Uint8(24)
uint8.eject(uint8.add(a, b)) // BigInt(280)
@ -51,12 +51,21 @@ uint8.eject(uint8.add(a, b)) // BigInt(280)
The overflow algorithm is based on how unsigned integer overflow is done in the C
language. In C it is not defined for signed integers, but this library defines it for all
ranged integers. In a nutshell:
ranged integers, using 2's complement for the builtin signed integers. The formula for
calculating the overflowed result is
1. Shift the range into a positive range, starting from 0.
1. Shift the value to overflow the same amount.
1. Do unsigned integer overflow or underflow.
1. Shift the answer back to the original range.
```
(value - min) % amount_of_values + min
```
where `min` is the minimum allowed value in the range, `amount_of_values` is the total
amount of allowed values, and `%` is the modulo (not remainder) operation.
In effect, for types that represent unsigned integers or 2's complement signed integers,
this is equivalent to truncating the value to the amount of bits that defines the range.
It's left up to the user to decide when overflowing makes sense, and to call `overflow`
when appropriate.
## The builtin types
@ -173,7 +182,7 @@ pub fn mvp_add_test() {
let assert Ok(a) = interface.from_bigint(bigi.from_int(2007), mvp.iface)
let b = bigi.from_int(9)
let c = interface.math_op(a, b, mvp.iface, bigi.add)
should.equal(c, Error(utils.DidOverflow(bigi.from_int(1))))
should.equal(c, Error(utils.WouldOverflow(bigi.from_int(1))))
}
```
@ -229,7 +238,12 @@ pub fn mvp2_add_test() {
let assert Ok(a) = mvp2.from_bigint(bigi.from_int(2007))
let b = bigi.from_int(9)
let c = mvp2.add(a, b)
should.equal(c, Error(utils.DidOverflow(bigi.from_int(1))))
should.equal(c, Error(utils.WouldOverflow(bigi.from_int(1))))
should.equal(
mvp2.overflow(c)
|> mvp2.to_bigint(),
bigi.from_int(2007),
)
}
```

View file

@ -14,7 +14,7 @@ repository = { type = "gitlab", user = "Nicd", repo = "ranged_int" }
[dependencies]
gleam_stdlib = "~> 0.34 or ~> 1.0"
bigi = "~> 1.0"
bigi = "~> 2.0"
[dev-dependencies]
gleeunit = "~> 1.0"

View file

@ -2,12 +2,12 @@
# You typically do not need to edit this file
packages = [
{ name = "bigi", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "bigi", source = "hex", outer_checksum = "CB2766365C3DA3C651AD55F6A6389A586FA6B2D66B80BE0DA168EEBD0EE1A43D" },
{ name = "bigi", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "bigi", source = "hex", outer_checksum = "E7841470F475D20B2EC2D4CB1167A8893AE943B6541809DCAB9D95FB471FDCDB" },
{ name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" },
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
]
[requirements]
bigi = { version = "~> 1.0"}
bigi = { version = "~> 2.0" }
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
gleeunit = { version = "~> 1.0" }

View file

@ -4,12 +4,10 @@
//// compile time. Generic ranged integers are less type safe and have lower
//// performance. It's always suggested to use one of the builtin types or to
//// create your own type when you can.
////
//// Any two-operand math operations will use the range of the first operand as
//// the range of the output value.
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, type Overflowable, Interface}
import ranged_int/builtin/uint
/// The interface of a generic ranged integer.
pub opaque type GenericInterface(overflow_mode) {
@ -79,16 +77,30 @@ pub fn divide(a: RangedInt(overflow_mode), b: BigInt) {
interface.math_op(a, b, a.interface(), bigi.divide)
}
pub fn divide_no_zero(a: RangedInt(overflow_mode), b: BigInt) {
interface.fallible_op(a, b, a.interface(), bigi.divide_no_zero)
}
pub fn modulo(a: RangedInt(overflow_mode), b: BigInt) {
interface.math_op(a, b, a.interface(), bigi.modulo)
}
pub fn modulo_no_zero(a: RangedInt(overflow_mode), b: BigInt) {
interface.fallible_op(a, b, a.interface(), bigi.modulo_no_zero)
}
pub fn remainder(a: RangedInt(overflow_mode), b: BigInt) {
interface.math_op(a, b, a.interface(), bigi.remainder)
}
pub fn power(a: RangedInt(overflow_mode), b: BigInt) {
interface.math_op(a, b, a.interface(), bigi.power)
pub fn remainder_no_zero(a: RangedInt(overflow_mode), b: BigInt) {
interface.fallible_op(a, b, a.interface(), bigi.remainder_no_zero)
}
pub fn power(a: RangedInt(overflow_mode), b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), a.interface(), bigi.power)
result
}
pub fn overflow(

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
pub opaque type Int128 {
Int128(data: BigInt)
@ -63,8 +64,10 @@ pub fn remainder_no_zero(a: Int128, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Int128, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Int128, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Int128)) {
@ -76,11 +79,8 @@ pub fn eject(op: interface.OpResult(Int128)) {
}
fn limits() {
let min =
bigi.multiply(
bigi.power(bigi.from_int(2), bigi.from_int(127)),
bigi.from_int(-1),
)
let assert Ok(b127) = bigi.power(bigi.from_int(2), bigi.from_int(127))
let min = bigi.multiply(b127, bigi.from_int(-1))
let max = bigi.subtract(bigi.absolute(min), bigi.from_int(1))
interface.overflowable_limits(min, max)

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
const max_limit = 32_767
@ -79,8 +80,10 @@ pub fn remainder_no_zero(a: Int16, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Int16, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Int16, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Int16)) {

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
const max_limit = 2_147_483_647
@ -79,8 +80,10 @@ pub fn remainder_no_zero(a: Int32, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Int32, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Int32, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Int32)) {

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
pub opaque type Int64 {
Int64(data: BigInt)
@ -63,8 +64,10 @@ pub fn remainder_no_zero(a: Int64, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Int64, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Int64, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Int64)) {
@ -76,11 +79,8 @@ pub fn eject(op: interface.OpResult(Int64)) {
}
fn limits() {
let min =
bigi.multiply(
bigi.power(bigi.from_int(2), bigi.from_int(63)),
bigi.from_int(-1),
)
let assert Ok(b63) = bigi.power(bigi.from_int(2), bigi.from_int(63))
let min = bigi.multiply(b63, bigi.from_int(-1))
let max = bigi.subtract(bigi.absolute(min), bigi.from_int(1))
interface.overflowable_limits(min, max)

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
const max_limit = 127
@ -79,8 +80,10 @@ pub fn remainder_no_zero(a: Int8, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Int8, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Int8, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Int8)) {

View file

@ -51,8 +51,10 @@ pub fn remainder(a: Uint, b: BigInt) {
interface.math_op(a, b, iface, bigi.remainder)
}
pub fn power(a: Uint, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Uint, b: Uint) {
let assert Ok(result) =
interface.fallible_op(a, to_bigint(b), iface, bigi.power)
result
}
pub fn eject(op: interface.OpResult(Uint)) {

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
pub opaque type Uint128 {
Uint128(data: BigInt)
@ -59,8 +60,10 @@ pub fn remainder_no_zero(a: Uint128, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Uint128, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Uint128, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Uint128)) {
@ -73,11 +76,8 @@ pub fn eject(op: interface.OpResult(Uint128)) {
fn limits() {
let min = bigi.zero()
let max =
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(128)),
bigi.from_int(1),
)
let assert Ok(b128) = bigi.power(bigi.from_int(2), bigi.from_int(128))
let max = bigi.subtract(b128, bigi.from_int(1))
interface.overflowable_limits(min, max)
}

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
const max_limit = 65_535
@ -75,8 +76,10 @@ pub fn remainder_no_zero(a: Uint16, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Uint16, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Uint16, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Uint16)) {

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
pub const max_limit = 4_294_967_295
@ -75,8 +76,10 @@ pub fn remainder_no_zero(a: Uint32, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Uint32, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Uint32, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Uint32)) {

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
pub opaque type Uint64 {
Uint64(data: BigInt)
@ -59,8 +60,10 @@ pub fn remainder_no_zero(a: Uint64, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Uint64, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Uint64, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Uint64)) {
@ -73,11 +76,8 @@ pub fn eject(op: interface.OpResult(Uint64)) {
fn limits() {
let min = bigi.zero()
let max =
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(64)),
bigi.from_int(1),
)
let assert Ok(b64) = bigi.power(bigi.from_int(2), bigi.from_int(64))
let max = bigi.subtract(b64, bigi.from_int(1))
interface.overflowable_limits(min, max)
}

View file

@ -1,5 +1,6 @@
import bigi.{type BigInt}
import ranged_int/interface.{type Interface, Interface}
import ranged_int/builtin/uint
const max_limit = 255
@ -75,8 +76,10 @@ pub fn remainder_no_zero(a: Uint8, b: BigInt) {
interface.fallible_op(a, b, iface, bigi.remainder_no_zero)
}
pub fn power(a: Uint8, b: BigInt) {
interface.math_op(a, b, iface, bigi.power)
pub fn power(a: Uint8, b: uint.Uint) {
let assert Ok(result) =
interface.fallible_op(a, uint.to_bigint(b), iface, bigi.power)
result
}
pub fn overflow(op: interface.OpResult(Uint8)) {

View file

@ -85,8 +85,8 @@ pub fn from_bigint(
let limits = interface.limits()
case limit.check_limits(value, min: limits.min, max: limits.max) {
NoOverflow -> Ok(interface.from_bigint_unsafe(value))
Overflow(amount) -> Error(utils.DidOverflow(amount))
Underflow(amount) -> Error(utils.DidUnderflow(amount))
Overflow(amount) -> Error(utils.WouldOverflow(amount))
Underflow(amount) -> Error(utils.WouldUnderflow(amount))
}
}
@ -111,8 +111,8 @@ pub fn math_op(
let result = op(int1, int2)
case limit.check_limits(result, min: limits.min, max: limits.max) {
NoOverflow -> Ok(interface.from_bigint_unsafe(result))
Overflow(amount) -> Error(utils.DidOverflow(amount))
Underflow(amount) -> Error(utils.DidUnderflow(amount))
Overflow(amount) -> Error(utils.WouldOverflow(amount))
Underflow(amount) -> Error(utils.WouldUnderflow(amount))
}
}
@ -127,8 +127,8 @@ pub fn math_op_unary(
let result = op(int)
case limit.check_limits(result, min: limits.min, max: limits.max) {
NoOverflow -> Ok(interface.from_bigint_unsafe(result))
Overflow(amount) -> Error(utils.DidOverflow(amount))
Underflow(amount) -> Error(utils.DidUnderflow(amount))
Overflow(amount) -> Error(utils.WouldOverflow(amount))
Underflow(amount) -> Error(utils.WouldUnderflow(amount))
}
}
@ -148,8 +148,8 @@ pub fn fallible_op(
use result <- result.try(op(int1, int2))
Ok(case limit.check_limits(result, min: limits.min, max: limits.max) {
NoOverflow -> Ok(interface.from_bigint_unsafe(result))
Overflow(amount) -> Error(utils.DidOverflow(amount))
Underflow(amount) -> Error(utils.DidUnderflow(amount))
Overflow(amount) -> Error(utils.WouldOverflow(amount))
Underflow(amount) -> Error(utils.WouldUnderflow(amount))
})
}
@ -178,9 +178,9 @@ pub fn eject(value: OpResult(a), interface: Interface(a, overflow_mode)) {
Ok(new_value) -> interface.to_bigint(new_value)
Error(overflow) -> {
case overflow, interface.limits() {
utils.DidOverflow(amount), Limits(max: limit.Bounded(max), ..) ->
utils.WouldOverflow(amount), Limits(max: limit.Bounded(max), ..) ->
bigi.add(max, amount)
utils.DidUnderflow(amount), Limits(min: limit.Bounded(min), ..) ->
utils.WouldUnderflow(amount), Limits(min: limit.Bounded(min), ..) ->
bigi.subtract(min, amount)
_, _ -> panic as "Overflowed but there was no corresponding limit (o_O)"
}

View file

@ -4,9 +4,9 @@ import bigi.{type BigInt}
/// range.
pub type Overflow {
/// The result was this much higher than the maximum allowed value.
DidOverflow(BigInt)
WouldOverflow(BigInt)
/// The result was this much lower than the minimum allowed value.
DidUnderflow(BigInt)
WouldUnderflow(BigInt)
}
/// Calculate the overflowed value given an overflow result and the limits.
@ -15,15 +15,13 @@ pub fn overflow(overflow: Overflow, min min: BigInt, max max: BigInt) -> BigInt
bigi.subtract(max, min)
|> bigi.add(bigi.from_int(1))
let min_adjustment_factor = bigi.multiply(min, bigi.from_int(-1))
let adjusted_max = bigi.add(max, min_adjustment_factor)
let adjusted_min = bigi.zero()
let overflowed_value = case overflow {
DidOverflow(amount) -> bigi.add(adjusted_max, amount)
DidUnderflow(amount) -> bigi.subtract(adjusted_min, amount)
let actual = case overflow {
WouldOverflow(amount) -> bigi.add(max, amount)
WouldUnderflow(amount) -> bigi.subtract(min, amount)
}
let overflow_result = bigi.modulo(overflowed_value, total_values)
bigi.subtract(overflow_result, min_adjustment_factor)
actual
|> bigi.subtract(min)
|> bigi.modulo(total_values)
|> bigi.add(min)
}

View file

@ -1,326 +0,0 @@
import gleam/function
import gleeunit/should
import bigi.{type BigInt}
import ranged_int/interface
import ranged_int/builtin/uint8
import ranged_int/builtin/uint16
import ranged_int/builtin/uint32
import ranged_int/builtin/uint64
import ranged_int/builtin/uint128
import ranged_int/builtin/int8
import ranged_int/builtin/int16
import ranged_int/builtin/int32
import ranged_int/builtin/int64
import ranged_int/builtin/int128
pub fn absolute_test() {
let input = bigi.from_int(-19)
let expected = bigi.from_int(19)
unary(int8.from_bigint, int8.absolute)(input, expected)
unary(int16.from_bigint, int16.absolute)(input, expected)
unary(int32.from_bigint, int32.absolute)(input, expected)
unary(int64.from_bigint, int64.absolute)(input, expected)
unary(int128.from_bigint, int128.absolute)(input, expected)
}
pub fn add_test() {
let input1 = bigi.from_int(1)
let input2 = bigi.from_int(12)
let expected = bigi.from_int(13)
binary(int8.from_bigint, int8.add)(
input1,
input2,
should.equal(_, int8.from_bigint(expected)),
)
binary(int16.from_bigint, int16.add)(
input1,
input2,
should.equal(_, int16.from_bigint(expected)),
)
binary(int32.from_bigint, int32.add)(
input1,
input2,
should.equal(_, int32.from_bigint(expected)),
)
binary(int64.from_bigint, int64.add)(
input1,
input2,
should.equal(_, int64.from_bigint(expected)),
)
binary(int128.from_bigint, int128.add)(
input1,
input2,
should.equal(_, int128.from_bigint(expected)),
)
binary(uint8.from_bigint, uint8.add)(
input1,
input2,
should.equal(_, uint8.from_bigint(expected)),
)
binary(uint16.from_bigint, uint16.add)(
input1,
input2,
should.equal(_, uint16.from_bigint(expected)),
)
binary(uint32.from_bigint, uint32.add)(
input1,
input2,
should.equal(_, uint32.from_bigint(expected)),
)
binary(uint64.from_bigint, uint64.add)(
input1,
input2,
should.equal(_, uint64.from_bigint(expected)),
)
binary(uint128.from_bigint, uint128.add)(
input1,
input2,
should.equal(_, uint128.from_bigint(expected)),
)
}
pub fn add_overflow_test() {
let input1 = bigi.zero()
let input2 = bigi.power(bigi.from_int(2), bigi.from_int(1024))
binary(int8.from_bigint, int8.add)(input1, input2, should.be_error)
binary(int16.from_bigint, int16.add)(input1, input2, should.be_error)
binary(int32.from_bigint, int32.add)(input1, input2, should.be_error)
binary(int64.from_bigint, int64.add)(input1, input2, should.be_error)
binary(int128.from_bigint, int128.add)(input1, input2, should.be_error)
binary(uint8.from_bigint, uint8.add)(input1, input2, should.be_error)
binary(uint16.from_bigint, uint16.add)(input1, input2, should.be_error)
binary(uint32.from_bigint, uint32.add)(input1, input2, should.be_error)
binary(uint64.from_bigint, uint64.add)(input1, input2, should.be_error)
binary(uint128.from_bigint, uint128.add)(input1, input2, should.be_error)
}
pub fn add_overflow_eject_test() {
binary(int8.from_bigint, int8.add)(
bigi.from_int(-127),
bigi.from_int(1000),
function.compose(int8.eject, should.equal(_, bigi.from_int(873))),
)
binary(int16.from_bigint, int16.add)(
bigi.from_int(32_767),
bigi.from_int(1),
function.compose(int16.eject, should.equal(_, bigi.from_int(32_768))),
)
binary(int32.from_bigint, int32.add)(
bigi.from_int(2_000_000_000),
bigi.from_int(3_000_000_000),
function.compose(int32.eject, should.equal(_, bigi.from_int(5_000_000_000))),
)
binary(int64.from_bigint, int64.add)(
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(63)),
bigi.from_int(1),
),
bigi.from_int(1),
function.compose(int64.eject, should.equal(_, bigi.power(
bigi.from_int(2),
bigi.from_int(63),
))),
)
binary(int128.from_bigint, int128.add)(
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(127)),
bigi.from_int(1),
),
bigi.from_int(1),
function.compose(int128.eject, should.equal(_, bigi.power(
bigi.from_int(2),
bigi.from_int(127),
))),
)
binary(uint8.from_bigint, uint8.add)(
bigi.from_int(0),
bigi.from_int(1000),
function.compose(uint8.eject, should.equal(_, bigi.from_int(1000))),
)
binary(uint16.from_bigint, uint16.add)(
bigi.from_int(32_768),
bigi.from_int(32_768),
function.compose(uint16.eject, should.equal(_, bigi.from_int(65_536))),
)
binary(uint32.from_bigint, uint32.add)(
bigi.from_int(2_000_000_000),
bigi.from_int(3_000_000_000),
function.compose(uint32.eject, should.equal(_, bigi.from_int(5_000_000_000))),
)
binary(uint64.from_bigint, uint64.add)(
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(64)),
bigi.from_int(1),
),
bigi.from_int(1),
function.compose(uint64.eject, should.equal(_, bigi.power(
bigi.from_int(2),
bigi.from_int(64),
))),
)
binary(uint128.from_bigint, uint128.add)(
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(128)),
bigi.from_int(1),
),
bigi.from_int(1),
function.compose(uint128.eject, should.equal(_, bigi.power(
bigi.from_int(2),
bigi.from_int(128),
))),
)
}
pub fn add_overflow_wrap_test() {
overflow_wrap(
bigi.from_int(127),
bigi.from_int(1),
bigi.from_int(-128),
int8.from_bigint,
int8.add,
int8.overflow,
)
overflow_wrap(
bigi.from_int(-32_768),
bigi.from_int(-1),
bigi.from_int(32_767),
int16.from_bigint,
int16.add,
int16.overflow,
)
overflow_wrap(
bigi.from_int(2_000_000_000),
bigi.from_int(3_000_000_000),
bigi.from_int(705_032_704),
int32.from_bigint,
int32.add,
int32.overflow,
)
overflow_wrap(
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(63)),
bigi.from_int(255),
),
bigi.from_int(255),
bigi.multiply(
bigi.power(bigi.from_int(2), bigi.from_int(63)),
bigi.from_int(-1),
),
int64.from_bigint,
int64.add,
int64.overflow,
)
overflow_wrap(
bigi.multiply(
bigi.power(bigi.from_int(2), bigi.from_int(127)),
bigi.from_int(-1),
),
bigi.power(bigi.from_int(2), bigi.from_int(128)),
bigi.multiply(
bigi.power(bigi.from_int(2), bigi.from_int(127)),
bigi.from_int(-1),
),
int128.from_bigint,
int128.add,
int128.overflow,
)
overflow_wrap(
bigi.from_int(255),
bigi.from_int(1),
bigi.zero(),
uint8.from_bigint,
uint8.add,
uint8.overflow,
)
overflow_wrap(
bigi.from_int(65_535),
bigi.from_int(1),
bigi.zero(),
uint16.from_bigint,
uint16.add,
uint16.overflow,
)
overflow_wrap(
bigi.from_int(2_000_000_000),
bigi.from_int(3_000_000_000),
bigi.from_int(705_032_704),
uint32.from_bigint,
uint32.add,
uint32.overflow,
)
overflow_wrap(
bigi.subtract(
bigi.power(bigi.from_int(2), bigi.from_int(64)),
bigi.from_int(1),
),
bigi.from_int(1),
bigi.zero(),
uint64.from_bigint,
uint64.add,
uint64.overflow,
)
overflow_wrap(
bigi.power(bigi.from_int(2), bigi.from_int(127)),
bigi.power(bigi.from_int(2), bigi.from_int(127)),
bigi.zero(),
uint128.from_bigint,
uint128.add,
uint128.overflow,
)
}
fn overflow_wrap(
int1: BigInt,
int2: BigInt,
expected: BigInt,
from_bigint: fn(BigInt) -> Result(a, b),
fun: fn(a, BigInt) -> interface.OpResult(a),
overflow: fn(interface.OpResult(a)) -> a,
) {
let assert Ok(expected) = from_bigint(expected)
should.equal(binary(from_bigint, fun)(int1, int2, overflow), expected)
}
fn unary(
from_bigint: fn(BigInt) -> Result(a, b),
fun: fn(a) -> interface.OpResult(a),
) {
fn(val: BigInt, expected: BigInt) {
let assert Ok(val) = from_bigint(val)
let assert Ok(expected) = from_bigint(expected)
let res = fun(val)
should.equal(res, Ok(expected))
}
}
fn binary(
from_bigint: fn(BigInt) -> Result(a, b),
fun: fn(a, BigInt) -> interface.OpResult(a),
) {
fn(val1: BigInt, val2: BigInt, check: fn(interface.OpResult(a)) -> any) {
let assert Ok(val1) = from_bigint(val1)
let res = fun(val1, val2)
check(res)
}
}

View file

@ -1,24 +1,116 @@
import gleam/int
import gleam/float
import bigi
import gleeunit/should
import ranged_int/builtin/generic
import ranged_int/builtin/uint
const min = -31_495
const max = -13_413
pub fn absolute_test() {
let int = from_int(min)
should.equal(
generic.to_bigint(generic.overflow(
generic.absolute(int),
generic.get_interface(int),
)),
bigi.from_int(-22_754),
)
}
pub fn add_test() {
let assert Ok(a) = generic.from_bigint_min(bigi.zero(), min: bigi.zero())
let b = bigi.from_int(12)
let iface = generic.get_interface(a)
let c = generic.eject(generic.add(a, b), iface)
should.equal(c, bigi.from_int(12))
let int1 = from_int(min)
let int2 = bigi.from_int(1)
let assert Ok(result) = generic.add(int1, int2)
should.equal(generic.to_bigint(result), bigi.from_int(min + 1))
}
pub fn overflow_test() {
let assert Ok(a) =
generic.from_bigint_overflowable(
bigi.from_int(-15),
min: bigi.from_int(-284),
max: bigi.from_int(-7),
)
let b = bigi.from_int(12)
let iface = generic.get_interface(a)
let c = generic.overflow(generic.add(a, b), iface)
should.equal(generic.to_bigint(c), bigi.from_int(-281))
pub fn subtract_test() {
let int1 = from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(result) = generic.subtract(int1, int2)
should.equal(generic.to_bigint(result), bigi.from_int(max - 1))
}
pub fn multiply_test() {
let int1 = from_int(max)
let int2 = bigi.from_int(2)
let assert Ok(result) = generic.multiply(int1, int2)
should.equal(generic.to_bigint(result), bigi.from_int(max * 2))
}
pub fn divide_test() {
let int1 = from_int(min)
let int2 = bigi.from_int(2)
let assert Ok(result) = generic.divide(int1, int2)
should.equal(generic.to_bigint(result), bigi.from_int(min / 2))
}
pub fn divide_no_zero_test() {
let int1 = from_int(min)
should.be_error(generic.divide_no_zero(int1, bigi.zero()))
let assert Ok(Ok(result)) = generic.divide_no_zero(int1, bigi.from_int(2))
should.equal(generic.to_bigint(result), bigi.from_int(min / 2))
}
pub fn modulo_test() {
let int1 = from_int(min)
let int2 = bigi.from_int(2)
should.equal(
generic.eject(generic.modulo(int1, int2), generic.get_interface(int1)),
bigi.from_int(1),
)
}
pub fn modulo_no_zero_test() {
let int1 = from_int(min)
should.be_error(generic.modulo_no_zero(int1, bigi.zero()))
let assert Ok(rem) = generic.modulo_no_zero(int1, bigi.from_int(2))
should.equal(
generic.eject(rem, generic.get_interface(int1)),
bigi.from_int(1),
)
}
pub fn remainder_test() {
let int1 = from_int(min)
let int2 = bigi.from_int(2)
should.equal(
generic.eject(generic.remainder(int1, int2), generic.get_interface(int1)),
bigi.from_int(-1),
)
}
pub fn remainder_no_zero_test() {
let int1 = from_int(min)
should.be_error(generic.remainder_no_zero(int1, bigi.zero()))
let assert Ok(rem) = generic.remainder_no_zero(int1, bigi.from_int(2))
should.equal(
generic.eject(rem, generic.get_interface(int1)),
bigi.from_int(-1),
)
}
pub fn power_test() {
let int1 = from_int(max)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
let assert Ok(expected) = int.power(max, 2.0)
should.equal(
generic.eject(generic.power(int1, int2), generic.get_interface(int1)),
bigi.from_int(float.truncate(expected)),
)
}
fn from_int(int: Int) {
let min = bigi.from_int(min)
let max = bigi.from_int(max)
let assert Ok(int) =
int
|> bigi.from_int()
|> generic.from_bigint_overflowable(min: min, max: max)
int
}

View file

@ -1,9 +1,113 @@
import bigi
import gleeunit/should
import ranged_int/builtin/int128
import ranged_int/builtin/uint
pub fn absolute_test() {
let assert Ok(int) = int128.from_bigint(bigi.from_int(-1))
should.equal(int128.absolute(int), int128.from_bigint(bigi.from_int(1)))
}
pub fn add_test() {
let assert Ok(a) = int128.from_bigint(bigi.from_int(-3_190_309_415))
let b = int128.absolute(a)
should.equal(b, int128.from_bigint(bigi.from_int(3_190_309_415)))
let assert Ok(int1) = int128.from_bigint(bigi.from_int(-1))
let assert int2 = bigi.from_int(1)
should.equal(int128.add(int1, int2), int128.from_bigint(bigi.from_int(0)))
}
pub fn subtract_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(-1))
let assert int2 = bigi.from_int(1)
should.equal(
int128.subtract(int1, int2),
int128.from_bigint(bigi.from_int(-2)),
)
}
pub fn multiply_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
int128.multiply(int1, int2),
int128.from_bigint(bigi.from_int(4)),
)
}
pub fn divide_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(-2))
let assert int2 = bigi.from_int(-2)
should.equal(int128.divide(int1, int2), int128.from_bigint(bigi.from_int(1)))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(2))
should.be_error(int128.divide_no_zero(int1, bigi.zero()))
should.equal(
int128.divide_no_zero(int1, bigi.from_int(2)),
Ok(int128.from_bigint(bigi.from_int(1))),
)
}
pub fn modulo_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(-2))
let assert int2 = bigi.from_int(-2)
should.equal(int128.modulo(int1, int2), int128.from_bigint(bigi.from_int(0)))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(2))
should.be_error(int128.modulo_no_zero(int1, bigi.zero()))
should.equal(
int128.modulo_no_zero(int1, bigi.from_int(2)),
Ok(int128.from_bigint(bigi.from_int(0))),
)
}
pub fn remainder_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(-2))
let assert int2 = bigi.from_int(-2)
should.equal(
int128.remainder(int1, int2),
int128.from_bigint(bigi.from_int(0)),
)
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(2))
should.be_error(int128.remainder_no_zero(int1, bigi.zero()))
should.equal(
int128.remainder_no_zero(int1, bigi.from_int(2)),
Ok(int128.from_bigint(bigi.from_int(0))),
)
}
pub fn power_test() {
let assert Ok(int1) = int128.from_bigint(bigi.from_int(-2))
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(int128.power(int1, int2), int128.from_bigint(bigi.from_int(4)))
}
pub fn overflow_test() {
let #(min, max) = minmax()
let assert Ok(int1) = int128.from_bigint(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = int128.from_bigint(min)
should.equal(int128.overflow(int128.add(int1, int2)), expected)
}
pub fn eject_test() {
let #(_min, max) = minmax()
let assert Ok(int1) = int128.from_bigint(max)
let int2 = bigi.from_int(1)
should.equal(
int128.eject(int128.add(int1, int2)),
bigi.add(max, bigi.from_int(1)),
)
}
fn minmax() {
let assert Ok(b127) = bigi.power(bigi.from_int(2), bigi.from_int(127))
let min = bigi.multiply(b127, bigi.from_int(-1))
let max = bigi.subtract(bigi.absolute(min), bigi.from_int(1))
#(min, max)
}

View file

@ -0,0 +1,95 @@
import bigi
import gleeunit/should
import ranged_int/builtin/int16
import ranged_int/builtin/uint
const min = -32_768
const max = 32_767
pub fn absolute_test() {
let assert Ok(int) = int16.from_int(-1)
should.equal(int16.absolute(int), int16.from_int(1))
}
pub fn add_test() {
let assert Ok(int1) = int16.from_int(-1)
let assert int2 = bigi.from_int(1)
should.equal(int16.add(int1, int2), int16.from_int(0))
}
pub fn subtract_test() {
let assert Ok(int1) = int16.from_int(-1)
let assert int2 = bigi.from_int(1)
should.equal(int16.subtract(int1, int2), int16.from_int(-2))
}
pub fn multiply_test() {
let assert Ok(int1) = int16.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(int16.multiply(int1, int2), int16.from_int(4))
}
pub fn divide_test() {
let assert Ok(int1) = int16.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int16.divide(int1, int2), int16.from_int(1))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = int16.from_int(2)
should.be_error(int16.divide_no_zero(int1, bigi.zero()))
should.equal(
int16.divide_no_zero(int1, bigi.from_int(2)),
Ok(int16.from_int(1)),
)
}
pub fn modulo_test() {
let assert Ok(int1) = int16.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int16.modulo(int1, int2), int16.from_int(0))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = int16.from_int(2)
should.be_error(int16.modulo_no_zero(int1, bigi.zero()))
should.equal(
int16.modulo_no_zero(int1, bigi.from_int(2)),
Ok(int16.from_int(0)),
)
}
pub fn remainder_test() {
let assert Ok(int1) = int16.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int16.remainder(int1, int2), int16.from_int(0))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = int16.from_int(2)
should.be_error(int16.remainder_no_zero(int1, bigi.zero()))
should.equal(
int16.remainder_no_zero(int1, bigi.from_int(2)),
Ok(int16.from_int(0)),
)
}
pub fn power_test() {
let assert Ok(int1) = int16.from_int(-2)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(int16.power(int1, int2), int16.from_int(4))
}
pub fn overflow_test() {
let assert Ok(int1) = int16.from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = int16.from_int(min)
should.equal(int16.overflow(int16.add(int1, int2)), expected)
}
pub fn eject_test() {
let assert Ok(int1) = int16.from_int(max)
let int2 = bigi.from_int(1)
should.equal(int16.eject(int16.add(int1, int2)), bigi.from_int(max + 1))
}

View file

@ -0,0 +1,95 @@
import bigi
import gleeunit/should
import ranged_int/builtin/int32
import ranged_int/builtin/uint
const min = -2_147_483_648
const max = 2_147_483_647
pub fn absolute_test() {
let assert Ok(int) = int32.from_int(-1)
should.equal(int32.absolute(int), int32.from_int(1))
}
pub fn add_test() {
let assert Ok(int1) = int32.from_int(-1)
let assert int2 = bigi.from_int(1)
should.equal(int32.add(int1, int2), int32.from_int(0))
}
pub fn subtract_test() {
let assert Ok(int1) = int32.from_int(-1)
let assert int2 = bigi.from_int(1)
should.equal(int32.subtract(int1, int2), int32.from_int(-2))
}
pub fn multiply_test() {
let assert Ok(int1) = int32.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(int32.multiply(int1, int2), int32.from_int(4))
}
pub fn divide_test() {
let assert Ok(int1) = int32.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int32.divide(int1, int2), int32.from_int(1))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = int32.from_int(2)
should.be_error(int32.divide_no_zero(int1, bigi.zero()))
should.equal(
int32.divide_no_zero(int1, bigi.from_int(2)),
Ok(int32.from_int(1)),
)
}
pub fn modulo_test() {
let assert Ok(int1) = int32.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int32.modulo(int1, int2), int32.from_int(0))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = int32.from_int(2)
should.be_error(int32.modulo_no_zero(int1, bigi.zero()))
should.equal(
int32.modulo_no_zero(int1, bigi.from_int(2)),
Ok(int32.from_int(0)),
)
}
pub fn remainder_test() {
let assert Ok(int1) = int32.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int32.remainder(int1, int2), int32.from_int(0))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = int32.from_int(2)
should.be_error(int32.remainder_no_zero(int1, bigi.zero()))
should.equal(
int32.remainder_no_zero(int1, bigi.from_int(2)),
Ok(int32.from_int(0)),
)
}
pub fn power_test() {
let assert Ok(int1) = int32.from_int(-2)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(int32.power(int1, int2), int32.from_int(4))
}
pub fn overflow_test() {
let assert Ok(int1) = int32.from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = int32.from_int(min)
should.equal(int32.overflow(int32.add(int1, int2)), expected)
}
pub fn eject_test() {
let assert Ok(int1) = int32.from_int(max)
let int2 = bigi.from_int(1)
should.equal(int32.eject(int32.add(int1, int2)), bigi.from_int(max + 1))
}

View file

@ -0,0 +1,104 @@
import bigi
import gleeunit/should
import ranged_int/builtin/int64
import ranged_int/builtin/uint
pub fn absolute_test() {
let assert Ok(int) = int64.from_bigint(bigi.from_int(-1))
should.equal(int64.absolute(int), int64.from_bigint(bigi.from_int(1)))
}
pub fn add_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(-1))
let assert int2 = bigi.from_int(1)
should.equal(int64.add(int1, int2), int64.from_bigint(bigi.from_int(0)))
}
pub fn subtract_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(-1))
let assert int2 = bigi.from_int(1)
should.equal(int64.subtract(int1, int2), int64.from_bigint(bigi.from_int(-2)))
}
pub fn multiply_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(int64.multiply(int1, int2), int64.from_bigint(bigi.from_int(4)))
}
pub fn divide_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(-2))
let assert int2 = bigi.from_int(-2)
should.equal(int64.divide(int1, int2), int64.from_bigint(bigi.from_int(1)))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(2))
should.be_error(int64.divide_no_zero(int1, bigi.zero()))
should.equal(
int64.divide_no_zero(int1, bigi.from_int(2)),
Ok(int64.from_bigint(bigi.from_int(1))),
)
}
pub fn modulo_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(-2))
let assert int2 = bigi.from_int(-2)
should.equal(int64.modulo(int1, int2), int64.from_bigint(bigi.from_int(0)))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(2))
should.be_error(int64.modulo_no_zero(int1, bigi.zero()))
should.equal(
int64.modulo_no_zero(int1, bigi.from_int(2)),
Ok(int64.from_bigint(bigi.from_int(0))),
)
}
pub fn remainder_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(-2))
let assert int2 = bigi.from_int(-2)
should.equal(int64.remainder(int1, int2), int64.from_bigint(bigi.from_int(0)))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(2))
should.be_error(int64.remainder_no_zero(int1, bigi.zero()))
should.equal(
int64.remainder_no_zero(int1, bigi.from_int(2)),
Ok(int64.from_bigint(bigi.from_int(0))),
)
}
pub fn power_test() {
let assert Ok(int1) = int64.from_bigint(bigi.from_int(-2))
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(int64.power(int1, int2), int64.from_bigint(bigi.from_int(4)))
}
pub fn overflow_test() {
let #(min, max) = minmax()
let assert Ok(int1) = int64.from_bigint(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = int64.from_bigint(min)
should.equal(int64.overflow(int64.add(int1, int2)), expected)
}
pub fn eject_test() {
let #(_min, max) = minmax()
let assert Ok(int1) = int64.from_bigint(max)
let int2 = bigi.from_int(1)
should.equal(
int64.eject(int64.add(int1, int2)),
bigi.add(max, bigi.from_int(1)),
)
}
fn minmax() {
let assert Ok(b63) = bigi.power(bigi.from_int(2), bigi.from_int(63))
let min = bigi.multiply(b63, bigi.from_int(-1))
let max = bigi.subtract(bigi.absolute(min), bigi.from_int(1))
#(min, max)
}

View file

@ -0,0 +1,95 @@
import bigi
import gleeunit/should
import ranged_int/builtin/int8
import ranged_int/builtin/uint
const min = -128
const max = 127
pub fn absolute_test() {
let assert Ok(int) = int8.from_int(-1)
should.equal(int8.absolute(int), int8.from_int(1))
}
pub fn add_test() {
let assert Ok(int1) = int8.from_int(-1)
let assert int2 = bigi.from_int(1)
should.equal(int8.add(int1, int2), int8.from_int(0))
}
pub fn subtract_test() {
let assert Ok(int1) = int8.from_int(-1)
let assert int2 = bigi.from_int(1)
should.equal(int8.subtract(int1, int2), int8.from_int(-2))
}
pub fn multiply_test() {
let assert Ok(int1) = int8.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(int8.multiply(int1, int2), int8.from_int(4))
}
pub fn divide_test() {
let assert Ok(int1) = int8.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int8.divide(int1, int2), int8.from_int(1))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = int8.from_int(2)
should.be_error(int8.divide_no_zero(int1, bigi.zero()))
should.equal(
int8.divide_no_zero(int1, bigi.from_int(2)),
Ok(int8.from_int(1)),
)
}
pub fn modulo_test() {
let assert Ok(int1) = int8.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int8.modulo(int1, int2), int8.from_int(0))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = int8.from_int(2)
should.be_error(int8.modulo_no_zero(int1, bigi.zero()))
should.equal(
int8.modulo_no_zero(int1, bigi.from_int(2)),
Ok(int8.from_int(0)),
)
}
pub fn remainder_test() {
let assert Ok(int1) = int8.from_int(-2)
let assert int2 = bigi.from_int(-2)
should.equal(int8.remainder(int1, int2), int8.from_int(0))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = int8.from_int(2)
should.be_error(int8.remainder_no_zero(int1, bigi.zero()))
should.equal(
int8.remainder_no_zero(int1, bigi.from_int(2)),
Ok(int8.from_int(0)),
)
}
pub fn power_test() {
let assert Ok(int1) = int8.from_int(-2)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(int8.power(int1, int2), int8.from_int(4))
}
pub fn overflow_test() {
let assert Ok(int1) = int8.from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = int8.from_int(min)
should.equal(int8.overflow(int8.add(int1, int2)), expected)
}
pub fn eject_test() {
let assert Ok(int1) = int8.from_int(max)
let int2 = bigi.from_int(1)
should.equal(int8.eject(int8.add(int1, int2)), bigi.from_int(max + 1))
}

View file

@ -0,0 +1,114 @@
import bigi
import gleeunit/should
import ranged_int/builtin/uint128
import ranged_int/builtin/uint
pub fn add_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(0))
let assert int2 = bigi.from_int(1)
should.equal(uint128.add(int1, int2), uint128.from_bigint(bigi.from_int(1)))
}
pub fn subtract_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(1))
let assert int2 = bigi.from_int(1)
should.equal(
uint128.subtract(int1, int2),
uint128.from_bigint(bigi.from_int(0)),
)
}
pub fn multiply_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
uint128.multiply(int1, int2),
uint128.from_bigint(bigi.from_int(4)),
)
}
pub fn divide_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
uint128.divide(int1, int2),
uint128.from_bigint(bigi.from_int(1)),
)
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
should.be_error(uint128.divide_no_zero(int1, bigi.zero()))
should.equal(
uint128.divide_no_zero(int1, bigi.from_int(2)),
Ok(uint128.from_bigint(bigi.from_int(1))),
)
}
pub fn modulo_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
uint128.modulo(int1, int2),
uint128.from_bigint(bigi.from_int(0)),
)
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
should.be_error(uint128.modulo_no_zero(int1, bigi.zero()))
should.equal(
uint128.modulo_no_zero(int1, bigi.from_int(2)),
Ok(uint128.from_bigint(bigi.from_int(0))),
)
}
pub fn remainder_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
uint128.remainder(int1, int2),
uint128.from_bigint(bigi.from_int(0)),
)
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
should.be_error(uint128.remainder_no_zero(int1, bigi.zero()))
should.equal(
uint128.remainder_no_zero(int1, bigi.from_int(2)),
Ok(uint128.from_bigint(bigi.from_int(0))),
)
}
pub fn power_test() {
let assert Ok(int1) = uint128.from_bigint(bigi.from_int(2))
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(uint128.power(int1, int2), uint128.from_bigint(bigi.from_int(4)))
}
pub fn overflow_test() {
let #(min, max) = minmax()
let assert Ok(int1) = uint128.from_bigint(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = uint128.from_bigint(min)
should.equal(uint128.overflow(uint128.add(int1, int2)), expected)
}
pub fn eject_test() {
let #(_min, max) = minmax()
let assert Ok(int1) = uint128.from_bigint(max)
let int2 = bigi.from_int(1)
should.equal(
uint128.eject(uint128.add(int1, int2)),
bigi.add(max, bigi.from_int(1)),
)
}
fn minmax() {
let assert Ok(b128) = bigi.power(bigi.from_int(2), bigi.from_int(128))
let min = bigi.zero()
let max = bigi.subtract(b128, bigi.from_int(1))
#(min, max)
}

View file

@ -1,10 +1,90 @@
import bigi
import gleeunit/should
import ranged_int/builtin/uint16
import ranged_int/builtin/uint
const min = 0
const max = 65_535
pub fn add_test() {
let assert Ok(a) = uint16.from_bigint(bigi.zero())
let b = bigi.from_int(12)
let c = uint16.eject(uint16.add(a, b))
should.equal(c, bigi.from_int(12))
let assert Ok(int1) = uint16.from_int(0)
let assert int2 = bigi.from_int(1)
should.equal(uint16.add(int1, int2), uint16.from_int(1))
}
pub fn subtract_test() {
let assert Ok(int1) = uint16.from_int(1)
let assert int2 = bigi.from_int(1)
should.equal(uint16.subtract(int1, int2), uint16.from_int(0))
}
pub fn multiply_test() {
let assert Ok(int1) = uint16.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint16.multiply(int1, int2), uint16.from_int(4))
}
pub fn divide_test() {
let assert Ok(int1) = uint16.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint16.divide(int1, int2), uint16.from_int(1))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = uint16.from_int(2)
should.be_error(uint16.divide_no_zero(int1, bigi.zero()))
should.equal(
uint16.divide_no_zero(int1, bigi.from_int(2)),
Ok(uint16.from_int(1)),
)
}
pub fn modulo_test() {
let assert Ok(int1) = uint16.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint16.modulo(int1, int2), uint16.from_int(0))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = uint16.from_int(2)
should.be_error(uint16.modulo_no_zero(int1, bigi.zero()))
should.equal(
uint16.modulo_no_zero(int1, bigi.from_int(2)),
Ok(uint16.from_int(0)),
)
}
pub fn remainder_test() {
let assert Ok(int1) = uint16.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint16.remainder(int1, int2), uint16.from_int(0))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = uint16.from_int(2)
should.be_error(uint16.remainder_no_zero(int1, bigi.zero()))
should.equal(
uint16.remainder_no_zero(int1, bigi.from_int(2)),
Ok(uint16.from_int(0)),
)
}
pub fn power_test() {
let assert Ok(int1) = uint16.from_int(2)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(uint16.power(int1, int2), uint16.from_int(4))
}
pub fn overflow_test() {
let assert Ok(int1) = uint16.from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = uint16.from_int(min)
should.equal(uint16.overflow(uint16.add(int1, int2)), expected)
}
pub fn eject_test() {
let assert Ok(int1) = uint16.from_int(max)
let int2 = bigi.from_int(1)
should.equal(uint16.eject(uint16.add(int1, int2)), bigi.from_int(max + 1))
}

View file

@ -0,0 +1,90 @@
import bigi
import gleeunit/should
import ranged_int/builtin/uint32
import ranged_int/builtin/uint
const min = 0
const max = 4_294_967_295
pub fn add_test() {
let assert Ok(int1) = uint32.from_int(0)
let assert int2 = bigi.from_int(1)
should.equal(uint32.add(int1, int2), uint32.from_int(1))
}
pub fn subtract_test() {
let assert Ok(int1) = uint32.from_int(1)
let assert int2 = bigi.from_int(1)
should.equal(uint32.subtract(int1, int2), uint32.from_int(0))
}
pub fn multiply_test() {
let assert Ok(int1) = uint32.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint32.multiply(int1, int2), uint32.from_int(4))
}
pub fn divide_test() {
let assert Ok(int1) = uint32.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint32.divide(int1, int2), uint32.from_int(1))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = uint32.from_int(2)
should.be_error(uint32.divide_no_zero(int1, bigi.zero()))
should.equal(
uint32.divide_no_zero(int1, bigi.from_int(2)),
Ok(uint32.from_int(1)),
)
}
pub fn modulo_test() {
let assert Ok(int1) = uint32.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint32.modulo(int1, int2), uint32.from_int(0))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = uint32.from_int(2)
should.be_error(uint32.modulo_no_zero(int1, bigi.zero()))
should.equal(
uint32.modulo_no_zero(int1, bigi.from_int(2)),
Ok(uint32.from_int(0)),
)
}
pub fn remainder_test() {
let assert Ok(int1) = uint32.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint32.remainder(int1, int2), uint32.from_int(0))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = uint32.from_int(2)
should.be_error(uint32.remainder_no_zero(int1, bigi.zero()))
should.equal(
uint32.remainder_no_zero(int1, bigi.from_int(2)),
Ok(uint32.from_int(0)),
)
}
pub fn power_test() {
let assert Ok(int1) = uint32.from_int(2)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(uint32.power(int1, int2), uint32.from_int(4))
}
pub fn overflow_test() {
let assert Ok(int1) = uint32.from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = uint32.from_int(min)
should.equal(uint32.overflow(uint32.add(int1, int2)), expected)
}
pub fn eject_test() {
let assert Ok(int1) = uint32.from_int(max)
let int2 = bigi.from_int(1)
should.equal(uint32.eject(uint32.add(int1, int2)), bigi.from_int(max + 1))
}

View file

@ -0,0 +1,108 @@
import bigi
import gleeunit/should
import ranged_int/builtin/uint64
import ranged_int/builtin/uint
pub fn add_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(0))
let assert int2 = bigi.from_int(1)
should.equal(uint64.add(int1, int2), uint64.from_bigint(bigi.from_int(1)))
}
pub fn subtract_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(1))
let assert int2 = bigi.from_int(1)
should.equal(
uint64.subtract(int1, int2),
uint64.from_bigint(bigi.from_int(0)),
)
}
pub fn multiply_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
uint64.multiply(int1, int2),
uint64.from_bigint(bigi.from_int(4)),
)
}
pub fn divide_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(uint64.divide(int1, int2), uint64.from_bigint(bigi.from_int(1)))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
should.be_error(uint64.divide_no_zero(int1, bigi.zero()))
should.equal(
uint64.divide_no_zero(int1, bigi.from_int(2)),
Ok(uint64.from_bigint(bigi.from_int(1))),
)
}
pub fn modulo_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(uint64.modulo(int1, int2), uint64.from_bigint(bigi.from_int(0)))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
should.be_error(uint64.modulo_no_zero(int1, bigi.zero()))
should.equal(
uint64.modulo_no_zero(int1, bigi.from_int(2)),
Ok(uint64.from_bigint(bigi.from_int(0))),
)
}
pub fn remainder_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
let assert int2 = bigi.from_int(2)
should.equal(
uint64.remainder(int1, int2),
uint64.from_bigint(bigi.from_int(0)),
)
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
should.be_error(uint64.remainder_no_zero(int1, bigi.zero()))
should.equal(
uint64.remainder_no_zero(int1, bigi.from_int(2)),
Ok(uint64.from_bigint(bigi.from_int(0))),
)
}
pub fn power_test() {
let assert Ok(int1) = uint64.from_bigint(bigi.from_int(2))
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(uint64.power(int1, int2), uint64.from_bigint(bigi.from_int(4)))
}
pub fn overflow_test() {
let #(min, max) = minmax()
let assert Ok(int1) = uint64.from_bigint(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = uint64.from_bigint(min)
should.equal(uint64.overflow(uint64.add(int1, int2)), expected)
}
pub fn eject_test() {
let #(_min, max) = minmax()
let assert Ok(int1) = uint64.from_bigint(max)
let int2 = bigi.from_int(1)
should.equal(
uint64.eject(uint64.add(int1, int2)),
bigi.add(max, bigi.from_int(1)),
)
}
fn minmax() {
let assert Ok(b64) = bigi.power(bigi.from_int(2), bigi.from_int(64))
let min = bigi.zero()
let max = bigi.subtract(b64, bigi.from_int(1))
#(min, max)
}

View file

@ -1,31 +1,90 @@
import bigi
import gleeunit/should
import ranged_int/builtin/uint8
import ranged_int/builtin/uint
const min = 0
const max = 255
pub fn add_test() {
let assert Ok(a) = uint8.from_bigint(bigi.zero())
let b = bigi.from_int(12)
let c = uint8.eject(uint8.add(a, b))
should.equal(c, bigi.from_int(12))
let assert Ok(int1) = uint8.from_int(0)
let assert int2 = bigi.from_int(1)
should.equal(uint8.add(int1, int2), uint8.from_int(1))
}
pub fn subtract_test() {
let assert Ok(int1) = uint8.from_int(1)
let assert int2 = bigi.from_int(1)
should.equal(uint8.subtract(int1, int2), uint8.from_int(0))
}
pub fn multiply_test() {
let assert Ok(int1) = uint8.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint8.multiply(int1, int2), uint8.from_int(4))
}
pub fn divide_test() {
let assert Ok(a) = uint8.from_int(120)
let b = bigi.from_int(12)
let assert Ok(c) = uint8.divide_no_zero(a, b)
should.equal(uint8.eject(c), bigi.from_int(10))
let assert Ok(int1) = uint8.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint8.divide(int1, int2), uint8.from_int(1))
}
pub fn divide_no_zero_test() {
let assert Ok(int1) = uint8.from_int(2)
should.be_error(uint8.divide_no_zero(int1, bigi.zero()))
should.equal(
uint8.divide_no_zero(int1, bigi.from_int(2)),
Ok(uint8.from_int(1)),
)
}
pub fn modulo_test() {
let assert Ok(int1) = uint8.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint8.modulo(int1, int2), uint8.from_int(0))
}
pub fn modulo_no_zero_test() {
let assert Ok(int1) = uint8.from_int(2)
should.be_error(uint8.modulo_no_zero(int1, bigi.zero()))
should.equal(
uint8.modulo_no_zero(int1, bigi.from_int(2)),
Ok(uint8.from_int(0)),
)
}
pub fn remainder_test() {
let assert Ok(int1) = uint8.from_int(2)
let assert int2 = bigi.from_int(2)
should.equal(uint8.remainder(int1, int2), uint8.from_int(0))
}
pub fn remainder_no_zero_test() {
let assert Ok(int1) = uint8.from_int(2)
should.be_error(uint8.remainder_no_zero(int1, bigi.zero()))
should.equal(
uint8.remainder_no_zero(int1, bigi.from_int(2)),
Ok(uint8.from_int(0)),
)
}
pub fn power_test() {
let assert Ok(int1) = uint8.from_int(2)
let assert Ok(int2) = uint.from_bigint(bigi.from_int(2))
should.equal(uint8.power(int1, int2), uint8.from_int(4))
}
pub fn overflow_test() {
let assert Ok(a) = uint8.from_int(120)
let b = bigi.from_int(160)
let c = uint8.overflow(uint8.add(a, b))
should.equal(uint8.to_int(c), 24)
let assert Ok(int1) = uint8.from_int(max)
let int2 = bigi.from_int(1)
let assert Ok(expected) = uint8.from_int(min)
should.equal(uint8.overflow(uint8.add(int1, int2)), expected)
}
pub fn underflow_test() {
let assert Ok(a) = uint8.from_bigint(bigi.from_int(120))
let b = bigi.from_int(160)
let c = uint8.overflow(uint8.subtract(a, b))
should.equal(uint8.to_bigint(c), bigi.from_int(216))
pub fn eject_test() {
let assert Ok(int1) = uint8.from_int(max)
let int2 = bigi.from_int(1)
should.equal(uint8.eject(uint8.add(int1, int2)), bigi.from_int(max + 1))
}

484
test/overflow_test.gleam Normal file
View file

@ -0,0 +1,484 @@
import gleam/list
import gleeunit/should
import bigi
import ranged_int/utils
const uint8_testset = [
#(112, 225, 81),
#(228, 195, 167),
#(179, 142, 65),
#(232, 68, 44),
#(220, 94, 58),
#(110, 147, 1),
#(103, 196, 43),
#(204, 212, 160),
#(109, 211, 64),
#(239, 57, 40),
#(137, 146, 27),
#(213, 62, 19),
#(110, 205, 59),
#(172, 131, 47),
#(97, 190, 31),
#(137, 203, 84),
#(249, 209, 202),
#(202, 107, 53),
#(158, 159, 61),
#(204, 253, 201),
#(184, 176, 104),
#(166, 221, 131),
#(209, 226, 179),
#(231, 117, 92),
#(171, 157, 72),
#(147, 229, 120),
#(239, 104, 87),
#(221, 112, 77),
#(240, 116, 100),
#(166, 247, 157),
#(198, 98, 40),
#(192, 229, 165),
#(200, 60, 4),
#(180, 85, 9),
#(171, 222, 137),
#(210, 57, 11),
#(86, 208, 38),
#(74, 236, 54),
#(206, 241, 191),
#(164, 100, 8),
#(244, 246, 234),
#(143, 246, 133),
#(131, 142, 17),
#(118, 194, 56),
#(31, 229, 4),
#(185, 145, 74),
#(121, 181, 46),
#(195, 190, 129),
#(248, 103, 95),
#(195, 125, 64),
#(143, 228, 115),
#(99, 182, 25),
#(171, 103, 18),
#(212, 107, 63),
#(48, 252, 44),
#(135, 157, 36),
#(104, 199, 47),
#(252, 136, 132),
#(219, 194, 157),
#(182, 95, 21),
#(110, 171, 25),
#(135, 244, 123),
#(56, 213, 13),
#(7, 251, 2),
#(53, 227, 24),
#(226, 194, 164),
#(150, 197, 91),
#(116, 181, 41),
#(89, 199, 32),
#(97, 234, 75),
#(114, 212, 70),
#(219, 197, 160),
#(232, 211, 187),
#(215, 236, 195),
#(153, 143, 40),
#(144, 225, 113),
#(134, 214, 92),
#(181, 179, 104),
#(105, 187, 36),
#(12, 247, 3),
#(250, 23, 17),
#(237, 89, 70),
#(233, 224, 201),
#(210, 236, 190),
#(233, 208, 185),
#(132, 172, 48),
#(197, 244, 185),
#(194, 143, 81),
#(232, 59, 35),
#(61, 214, 19),
#(224, 105, 73),
#(208, 62, 14),
#(165, 191, 100),
#(253, 245, 242),
#(142, 201, 87),
#(220, 55, 19),
#(249, 195, 188),
#(57, 230, 31),
#(192, 250, 186),
#(248, 132, 124),
]
const uint16_testset = [
#(53_507, 23_855, 11_826),
#(46_924, 25_977, 7365),
#(65_063, 53_609, 53_136),
#(57_356, 40_806, 32_626),
#(57_039, 42_996, 34_499),
#(52_094, 44_757, 31_315),
#(51_826, 58_047, 44_337),
#(34_558, 36_127, 5149),
#(46_715, 50_409, 31_588),
#(47_464, 37_618, 19_546),
#(5454, 61_708, 1626),
#(58_546, 38_113, 31_123),
#(42_084, 32_688, 9236),
#(41_435, 25_026, 925),
#(30_086, 54_929, 19_479),
#(23_497, 52_484, 10_445),
#(53_057, 27_358, 14_879),
#(39_282, 27_525, 1271),
#(14_626, 63_958, 13_048),
#(22_728, 54_372, 11_564),
#(45_820, 22_584, 2868),
#(43_481, 47_301, 25_246),
#(60_280, 43_875, 38_619),
#(46_998, 64_467, 45_929),
#(64_531, 3171, 2166),
#(22_327, 45_778, 2569),
#(44_104, 57_573, 36_141),
#(53_933, 21_452, 9849),
#(28_246, 64_724, 27_434),
#(63_087, 61_533, 59_084),
#(62_571, 23_304, 20_339),
#(51_536, 21_086, 7086),
#(45_994, 54_043, 34_501),
#(20_775, 64_334, 19_573),
#(41_124, 42_995, 18_583),
#(65_170, 11_754, 11_388),
#(9262, 62_579, 6305),
#(50_708, 26_924, 12_096),
#(48_199, 55_200, 37_863),
#(60_936, 43_822, 39_222),
#(60_862, 47_890, 43_216),
#(50_526, 36_306, 21_296),
#(24_522, 48_247, 7233),
#(45_165, 28_277, 7906),
#(48_854, 42_715, 26_033),
#(18_201, 47_541, 206),
#(48_568, 25_429, 8461),
#(57_765, 30_968, 23_197),
#(56_158, 38_031, 28_653),
#(22_481, 60_589, 17_534),
#(60_561, 35_159, 30_184),
#(60_390, 46_931, 41_785),
#(42_584, 51_757, 28_805),
#(50_536, 16_272, 1272),
#(47_834, 27_980, 10_278),
#(54_982, 15_731, 5177),
#(30_296, 42_947, 7707),
#(36_689, 63_208, 34_361),
#(32_499, 62_076, 29_039),
#(65_165, 31_455, 31_084),
#(58_090, 20_060, 12_614),
#(53_436, 29_679, 17_579),
#(41_189, 44_383, 20_036),
#(36_593, 52_979, 24_036),
#(39_633, 61_750, 35_847),
#(35_551, 33_517, 3532),
#(20_920, 63_223, 18_607),
#(58_628, 40_720, 33_812),
#(18_784, 60_975, 14_223),
#(52_625, 21_870, 8959),
#(28_227, 63_187, 25_878),
#(30_310, 50_085, 14_859),
#(49_863, 42_716, 27_043),
#(62_185, 54_112, 50_761),
#(43_652, 33_395, 11_511),
#(56_274, 22_812, 13_550),
#(36_147, 49_560, 20_171),
#(57_354, 14_989, 6807),
#(54_674, 24_884, 14_022),
#(53_699, 50_088, 38_251),
#(38_902, 37_979, 11_345),
#(62_742, 64_319, 61_525),
#(54_841, 12_958, 2263),
#(7886, 63_011, 5361),
#(58_935, 21_019, 14_418),
#(47_831, 26_851, 9146),
#(45_962, 39_335, 19_761),
#(53_975, 11_981, 420),
#(26_477, 58_093, 19_034),
#(44_588, 53_937, 32_989),
#(61_810, 49_637, 45_911),
#(19_980, 62_256, 16_700),
#(64_110, 17_762, 16_336),
#(4497, 61_449, 410),
#(40_318, 38_443, 13_225),
#(62_311, 39_529, 36_304),
#(18_039, 64_797, 17_300),
#(18_179, 52_010, 4653),
#(52_719, 26_144, 13_327),
#(48_750, 32_082, 15_296),
]
const int8_multiply_testset = [
#(87, 66, 110),
#(47, 34, 62),
#(-12, -81, -52),
#(76, 75, 68),
#(-16, -74, -96),
#(-66, -59, 54),
#(46, 48, -96),
#(-73, -118, -90),
#(120, 8, -64),
#(68, 120, -32),
#(92, 87, 68),
#(-47, -85, -101),
#(74, 72, -48),
#(-127, -43, 85),
#(97, 108, -20),
#(37, 12, -68),
#(120, 67, 104),
#(97, 19, 51),
#(-62, -96, 64),
#(-99, -84, 124),
#(-14, -103, -94),
#(106, 66, 84),
#(-21, -49, 5),
#(40, 73, 104),
#(61, 91, -81),
#(-5, -81, -107),
#(-69, -22, -18),
#(11, 35, -127),
#(-112, -14, 32),
#(-15, -90, 70),
#(53, 3, -97),
#(126, 88, 80),
#(38, 32, -64),
#(-114, -65, -14),
#(31, 71, -103),
#(8, 35, 24),
#(34, 96, -64),
#(23, 103, 65),
#(-32, -102, -64),
#(112, 87, 16),
#(-45, -15, -93),
#(75, 15, 101),
#(-32, -106, 64),
#(11, 109, -81),
#(99, 30, -102),
#(88, 51, -120),
#(-38, -112, -96),
#(78, 107, -102),
#(52, 55, 44),
#(96, 103, -96),
#(-55, -110, -94),
#(42, 42, -28),
#(-109, -83, 87),
#(117, 124, -84),
#(49, 108, -84),
#(17, 93, 45),
#(-75, -81, -69),
#(122, 115, -50),
#(-91, -33, -69),
#(113, 74, -86),
#(-99, -44, 4),
#(-10, -73, -38),
#(-75, -104, 120),
#(18, 59, 38),
#(-77, -18, 106),
#(-95, -6, 58),
#(-125, -37, 17),
#(-99, -42, 62),
#(118, 110, -76),
#(-22, -53, -114),
#(-89, -128, -128),
#(101, 57, 125),
#(100, 79, -36),
#(18, 32, 64),
#(-19, -12, -28),
#(90, 120, 48),
#(57, 20, 116),
#(-47, -85, -101),
#(-69, -102, 126),
#(62, 23, -110),
#(116, 34, 104),
#(105, 32, 32),
#(-22, -7, -102),
#(-70, -68, -104),
#(-10, -42, -92),
#(-5, -75, 119),
#(115, 42, -34),
#(-85, -9, -3),
#(-80, -11, 112),
#(76, 51, 36),
#(106, 5, 18),
#(117, 27, 87),
#(10, 113, 106),
#(-40, -116, 32),
#(-43, -6, 2),
#(97, 105, -55),
#(-12, -65, 12),
#(-55, -118, 90),
#(-46, -55, -30),
#(70, 93, 110),
]
const int8_underflow_testset = [
#(-57, 92, 107),
#(-123, 11, 122),
#(-115, 48, 93),
#(-128, 52, 76),
#(-125, 105, 26),
#(-76, 78, 102),
#(-76, 92, 88),
#(-46, 101, 109),
#(-110, 80, 66),
#(-62, 80, 114),
#(-75, 77, 104),
#(-127, 54, 75),
#(-121, 121, 14),
#(-127, 3, 126),
#(-72, 68, 116),
#(-93, 83, 80),
#(-110, 112, 34),
#(-83, 59, 114),
#(-124, 109, 23),
#(-121, 81, 54),
#(-72, 105, 79),
#(-106, 104, 46),
#(-122, 78, 56),
#(-99, 40, 117),
#(-88, 83, 85),
#(-68, 97, 91),
#(-106, 93, 57),
#(-94, 57, 105),
#(-78, 125, 53),
#(-122, 71, 63),
#(-80, 97, 79),
#(-118, 51, 87),
#(-83, 79, 94),
#(-122, 100, 34),
#(-102, 49, 105),
#(-84, 87, 85),
#(-56, 111, 89),
#(-82, 56, 118),
#(-111, 58, 87),
#(-117, 29, 110),
#(-112, 57, 87),
#(-115, 34, 107),
#(-92, 100, 64),
#(-107, 99, 50),
#(-49, 124, 83),
#(-125, 104, 27),
#(-116, 122, 18),
#(-116, 121, 19),
#(-128, 74, 54),
#(-34, 102, 120),
#(-126, 56, 74),
#(-63, 68, 125),
#(-13, 116, 127),
#(-82, 59, 115),
#(-99, 84, 73),
#(-65, 77, 114),
#(-128, 113, 15),
#(-100, 124, 32),
#(-63, 104, 89),
#(-120, 53, 83),
#(-80, 86, 90),
#(-36, 101, 119),
#(-78, 97, 81),
#(-80, 74, 102),
#(-52, 105, 99),
#(-76, 104, 76),
#(-121, 110, 25),
#(-102, 35, 119),
#(-35, 122, 99),
#(-118, 100, 38),
#(-82, 111, 63),
#(-18, 115, 123),
#(-81, 105, 70),
#(-113, 79, 64),
#(-49, 104, 103),
#(-44, 94, 118),
#(-46, 85, 125),
#(-51, 81, 124),
#(-50, 115, 91),
#(-50, 105, 101),
#(-49, 123, 84),
#(-97, 91, 68),
#(-89, 67, 100),
#(-93, 85, 78),
#(-91, 91, 74),
#(-102, 38, 116),
#(-116, 17, 123),
#(-23, 110, 123),
#(-45, 95, 116),
#(-65, 82, 109),
#(-126, 85, 45),
#(-33, 123, 100),
#(-68, 113, 75),
#(-80, 104, 72),
#(-127, 49, 80),
#(-108, 112, 36),
#(-123, 114, 19),
#(-76, 75, 105),
#(-82, 70, 104),
#(-114, 76, 66),
]
pub fn uint8_overflow_test() {
list.each(uint8_testset, fn(data) {
let a = bigi.from_int(data.0)
let b = bigi.from_int(data.1)
let c = bigi.add(a, b)
let d = bigi.subtract(c, bigi.from_int(255))
should.equal(
utils.overflow(
utils.WouldOverflow(d),
min: bigi.zero(),
max: bigi.from_int(255),
),
bigi.from_int(data.2),
)
})
}
pub fn uint16_overflow_test() {
list.each(uint16_testset, fn(data) {
let a = bigi.from_int(data.0)
let b = bigi.from_int(data.1)
let c = bigi.add(a, b)
let d = bigi.subtract(c, bigi.from_int(65_535))
should.equal(
utils.overflow(
utils.WouldOverflow(d),
min: bigi.zero(),
max: bigi.from_int(65_535),
),
bigi.from_int(data.2),
)
})
}
pub fn int8_overflow_test() {
list.each(int8_multiply_testset, fn(data) {
let a = bigi.from_int(data.0)
let b = bigi.from_int(data.1)
let c = bigi.multiply(a, b)
let d = bigi.subtract(c, bigi.from_int(127))
should.equal(
utils.overflow(
utils.WouldOverflow(d),
min: bigi.from_int(-128),
max: bigi.from_int(127),
),
bigi.from_int(data.2),
)
})
}
pub fn int8_underflow_test() {
list.each(int8_underflow_testset, fn(data) {
let a = bigi.from_int(data.0)
let b = bigi.from_int(data.1)
let c = bigi.subtract(a, b)
let d = bigi.absolute(bigi.subtract(c, bigi.from_int(-128)))
should.equal(
utils.overflow(
utils.WouldUnderflow(d),
min: bigi.from_int(-128),
max: bigi.from_int(127),
),
bigi.from_int(data.2),
)
})
}

View file

@ -41,3 +41,7 @@ pub fn from_bigint(value: BigInt) {
pub fn compare(a: Katzen, b: Katzen) {
interface.compare(a, b, iface)
}
pub fn overflow(res: interface.OpResult(Katzen)) {
interface.overflow(res, iface)
}

View file

@ -15,5 +15,10 @@ pub fn mvp2_add_test() {
let assert Ok(a) = mvp2.from_bigint(bigi.from_int(2007))
let b = bigi.from_int(9)
let c = mvp2.add(a, b)
should.equal(c, Error(utils.DidOverflow(bigi.from_int(1))))
should.equal(c, Error(utils.WouldOverflow(bigi.from_int(1))))
should.equal(
mvp2.overflow(c)
|> mvp2.to_bigint(),
bigi.from_int(2007),
)
}

View file

@ -16,5 +16,5 @@ pub fn mvp_add_test() {
let assert Ok(a) = interface.from_bigint(bigi.from_int(2007), mvp.iface)
let b = bigi.from_int(9)
let c = interface.math_op(a, b, mvp.iface, bigi.add)
should.equal(c, Error(utils.DidOverflow(bigi.from_int(1))))
should.equal(c, Error(utils.WouldOverflow(bigi.from_int(1))))
}

36
test/testgen/main.cc Normal file
View file

@ -0,0 +1,36 @@
#include <iostream>
#include <random>
#include <cmath>
#include <cstdint>
const auto NUMS = 100;
int8_t generateRandomNumber(unsigned int numBits) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dist(-128, 127);
return dist(gen);
}
int modulo(int a, int b) {
const int result = a % b;
return result >= 0 ? result : result + b;
}
int main() {
auto numsSoFar = 0;
while (numsSoFar < NUMS) {
int8_t num1 = generateRandomNumber(8);
int8_t num2 = generateRandomNumber(8);
int32_t sum = num1 - num2;
if (sum < -128) {
// Overflow occurred, adjust the sum
int8_t over = sum;
std::cout << "#(" << (int) num1 << ", " << (int) num2 << ", " << (int) over << ")," << std::endl;
++numsSoFar;
}
}
return 0;
}