~sircmpwn/hare

9f2a23b73fce3f0175de54939ad59655e9414fca — Haelwenn (lanodan) Monnier 2 years ago d858829
math: make absi* functions return an unsigned integer

This allows to avoid abs actually returning a negative integer while also
avoiding overflows.

Signed-off-by: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Signed-off-by: Drew DeVault <sir@cmpwn.com>
1 files changed, 54 insertions(+), 39 deletions(-)

M math/ints.ha
M math/ints.ha => math/ints.ha +54 -39
@@ 1,74 1,89 @@
use types;

// Returns the absolute value of signed integer n.
export fn absi8(n: i8) i8 = {
export fn absi8(n: i8) u8 = {
	if (n < 0i8) {
		return -n;
		return -n: u8;
	} else {
		return n;
		return n: u8;
	};
};

// Returns the absolute value of signed integer n.
export fn absi16(n: i16) i16 = {
export fn absi16(n: i16) u16 = {
	if (n < 0i16) {
		return -n;
		return -n: u16;
	} else {
		return n;
		return n: u16;
	};
};

// Returns the absolute value of signed integer n.
export fn absi32(n: i32) i32 = {
export fn absi32(n: i32) u32 = {
	if (n < 0i32) {
		return -n;
		return -n: u32;
	} else {
		return n;
		return n: u32;
	};
};

// Returns the absolute value of signed integer n.
export fn absi64(n: i64) i64 = {
export fn absi64(n: i64) u64 = {
	if (n < 0i64) {
		return -n;
		return -n: u64;
	} else {
		return n;
		return n: u64;
	};
};

// Returns the absolute value of signed integer n.
export fn absi(n: types::integer) i64 = {
export fn absi(n: types::integer) u64 = {
	match (n) {
	case let n: i8 =>
		return (absi8(n): i64);
		return absi8(n): u64;
	case let n: i16 =>
		return (absi16(n): i64);
		return absi16(n): u64;
	case let n: i32 =>
		return (absi32(n): i64);
		return absi32(n): u64;
	case let n: i64 =>
		return (absi64(n): i64);
		return absi64(n): u64;
	case let n: int =>
		return (absi64(n): i64);
		return absi64(n): u64;
	};
};

@test fn absi() void = {
	assert(absi8(2i8) == 2i8);
	assert(absi8(-2i8) == 2i8);
	assert(absi16(2i16) == 2i16);
	assert(absi16(-2i16) == 2i16);
	assert(absi32(2i32) == 2i32);
	assert(absi32(-2i32) == 2i32);
	assert(absi64(2i64) == 2i64);
	assert(absi64(-2i64) == 2i64);
	assert(absi(2i8) == 2i64);
	assert(absi(-2i8) == 2i64);
	assert(absi(2i16) == 2i64);
	assert(absi(-2i16) == 2i64);
	assert(absi(2i32) == 2i64);
	assert(absi(-2i32) == 2i64);
	assert(absi(2i64) == 2i64);
	assert(absi(-2i64) == 2i64);
	// Workaround casting issue where (-types::I8_MIN: u8) has a value not
	// equal to (-types::I8_MIN: u16)
	let m8 = (-types::I8_MIN: u8);
	let m16 = (-types::I16_MIN: u16);
	let m32 = (-types::I32_MIN: u32);
	let m64 = (-types::I64_MIN: u64);

	assert(absi8(2i8) == 2u8);
	assert(absi8(-2i8) == 2u8);
	assert(absi8(types::I8_MIN) == m8);
	assert(absi16(2i16) == 2u16);
	assert(absi16(-2i16) == 2u16);
	assert(absi16(types::I16_MIN) == m16);
	assert(absi32(2i32) == 2u32);
	assert(absi32(-2i32) == 2u32);
	assert(absi32(types::I32_MIN) == m32);
	assert(absi64(2i64) == 2u64);
	assert(absi64(-2i64) == 2u64);
	assert(absi64(types::I64_MIN) == m64);
	assert(absi(2i8) == 2u64);
	assert(absi(-2i8) == 2u64);
	assert(absi(types::I8_MIN) == (m8: u64));
	assert(absi(2i16) == 2u64);
	assert(absi(-2i16) == 2u64);
	assert(absi(types::I16_MIN) == (m16: u64));
	assert(absi(2i32) == 2u64);
	assert(absi(-2i32) == 2u64);
	assert(absi(types::I32_MIN) == (m32: u64));
	assert(absi(2i64) == 2u64);
	assert(absi(-2i64) == 2u64);
	assert(absi(types::I64_MIN) == (m64: u64));
};

// Return 1 if n is positive, -1 if it's negative and 0 if it's 0.


@@ 119,15 134,15 @@ export fn signi64(n: i64) i64 = {
export fn signi(n: types::integer) i64 = {
	match (n) {
	case let n: i8 =>
		return (signi8(n): i64);
		return signi8(n): i64;
	case let n: i16 =>
		return (signi16(n): i64);
		return signi16(n): i64;
	case let n: i32 =>
		return (signi32(n): i64);
		return signi32(n): i64;
	case let n: i64 =>
		return (signi64(n): i64);
		return signi64(n): i64;
	case let n: int =>
		return (signi64(n): i64);
		return signi64(n): i64;
	};
};