Add unary ops and to_int

This commit is contained in:
Mikko Ahlroth 2024-02-13 20:51:13 +02:00
parent 10c6a15aea
commit 2e9eb0851b
12 changed files with 124 additions and 3 deletions

View file

@ -59,6 +59,10 @@ pub fn compare(a: RangedInt(overflow_mode), b: RangedInt(overflow_mode)) {
interface.compare(a, b, a.interface())
}
pub fn absolute(a: RangedInt(overflow_mode)) {
interface.math_op_unary(a, a.interface(), bigi.absolute)
}
pub fn add(a: RangedInt(overflow_mode), b: BigInt) {
interface.math_op(a, b, a.interface(), bigi.add)
}

View file

@ -23,6 +23,10 @@ pub fn compare(a: Int128, b: Int128) {
interface.compare(a, b, iface)
}
pub fn absolute(a: Int128) {
interface.math_op_unary(a, iface, bigi.absolute)
}
pub fn add(a: Int128, b: BigInt) {
interface.math_op(a, b, iface, bigi.add)
}

View file

@ -15,6 +15,18 @@ const iface: Interface(Int16, interface.Overflowable) = Interface(
limits: limits,
)
pub fn from_int(value: Int) {
from_bigint(bigi.from_int(value))
}
pub fn to_int(uint: Int16) {
let assert Ok(int) =
uint
|> to_bigint()
|> bigi.to_int()
int
}
pub fn from_bigint(value: BigInt) {
interface.from_bigint(value, iface)
}
@ -27,6 +39,10 @@ pub fn compare(a: Int16, b: Int16) {
interface.compare(a, b, iface)
}
pub fn absolute(a: Int16) {
interface.math_op_unary(a, iface, bigi.absolute)
}
pub fn add(a: Int16, b: BigInt) {
interface.math_op(a, b, iface, bigi.add)
}

View file

@ -15,6 +15,18 @@ const iface: Interface(Int32, interface.Overflowable) = Interface(
limits: limits,
)
pub fn from_int(value: Int) {
from_bigint(bigi.from_int(value))
}
pub fn to_int(uint: Int32) {
let assert Ok(int) =
uint
|> to_bigint()
|> bigi.to_int()
int
}
pub fn from_bigint(value: BigInt) {
interface.from_bigint(value, iface)
}
@ -27,6 +39,10 @@ pub fn compare(a: Int32, b: Int32) {
interface.compare(a, b, iface)
}
pub fn absolute(a: Int32) {
interface.math_op_unary(a, iface, bigi.absolute)
}
pub fn add(a: Int32, b: BigInt) {
interface.math_op(a, b, iface, bigi.add)
}

View file

@ -23,6 +23,10 @@ pub fn compare(a: Int64, b: Int64) {
interface.compare(a, b, iface)
}
pub fn absolute(a: Int64) {
interface.math_op_unary(a, iface, bigi.absolute)
}
pub fn add(a: Int64, b: BigInt) {
interface.math_op(a, b, iface, bigi.add)
}

View file

@ -15,6 +15,18 @@ const iface: Interface(Int8, interface.Overflowable) = Interface(
limits: limits,
)
pub fn from_int(value: Int) {
from_bigint(bigi.from_int(value))
}
pub fn to_int(uint: Int8) {
let assert Ok(int) =
uint
|> to_bigint()
|> bigi.to_int()
int
}
pub fn from_bigint(value: BigInt) {
interface.from_bigint(value, iface)
}
@ -27,6 +39,10 @@ pub fn compare(a: Int8, b: Int8) {
interface.compare(a, b, iface)
}
pub fn absolute(a: Int8) {
interface.math_op_unary(a, iface, bigi.absolute)
}
pub fn add(a: Int8, b: BigInt) {
interface.math_op(a, b, iface, bigi.add)
}

View file

@ -15,6 +15,18 @@ const iface: Interface(Uint16, interface.Overflowable) = Interface(
limits: limits,
)
pub fn from_int(value: Int) {
from_bigint(bigi.from_int(value))
}
pub fn to_int(uint: Uint16) {
let assert Ok(int) =
uint
|> to_bigint()
|> bigi.to_int()
int
}
pub fn from_bigint(value: BigInt) {
interface.from_bigint(value, iface)
}

View file

@ -15,6 +15,18 @@ const iface: Interface(Uint32, interface.Overflowable) = Interface(
limits: limits,
)
pub fn from_int(value: Int) {
from_bigint(bigi.from_int(value))
}
pub fn to_int(uint: Uint32) {
let assert Ok(int) =
uint
|> to_bigint()
|> bigi.to_int()
int
}
pub fn from_bigint(value: BigInt) {
interface.from_bigint(value, iface)
}

View file

@ -15,6 +15,18 @@ const iface: Interface(Uint8, interface.Overflowable) = Interface(
limits: limits,
)
pub fn from_int(value: Int) {
from_bigint(bigi.from_int(value))
}
pub fn to_int(uint: Uint8) {
let assert Ok(int) =
uint
|> to_bigint()
|> bigi.to_int()
int
}
pub fn from_bigint(value: BigInt) {
interface.from_bigint(value, iface)
}

View file

@ -116,6 +116,22 @@ pub fn math_op(
}
}
/// Run a unary math operation on a ranged integer.
pub fn math_op_unary(
int: a,
interface: Interface(a, overflow_mode),
op: fn(BigInt) -> BigInt,
) -> OpResult(a) {
let limits = interface.limits()
let int = interface.to_bigint(int)
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))
}
}
/// Run a math operation that may fail on a ranged integer and an unranged big
/// integer.
///

View file

@ -0,0 +1,9 @@
import bigi
import gleeunit/should
import ranged_int/builtin/int128
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)))
}

View file

@ -10,17 +10,17 @@ pub fn add_test() {
}
pub fn divide_test() {
let assert Ok(a) = uint8.from_bigint(bigi.from_int(120))
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))
}
pub fn overflow_test() {
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)
let c = uint8.overflow(uint8.add(a, b))
should.equal(uint8.to_bigint(c), bigi.from_int(24))
should.equal(uint8.to_int(c), 24)
}
pub fn underflow_test() {