Skip to content

Commit

Permalink
Signed integers (FuelLabs#2340)
Browse files Browse the repository at this point in the history
i8, i16, i32, i64

Basic arithmetic operations and tests

Closes FuelLabs#2422

Co-authored-by: tyshkor <[email protected]>
Co-authored-by: Joshua Batty <[email protected]>
Co-authored-by: Alex Hansen <[email protected]>
Co-authored-by: SwayStar123 <[email protected]>
Co-authored-by: Simon <[email protected]>
  • Loading branch information
6 people authored Sep 26, 2022
1 parent 1620cb4 commit 283f196
Show file tree
Hide file tree
Showing 31 changed files with 1,313 additions and 0 deletions.
155 changes: 155 additions & 0 deletions sway-lib-std/src/i128.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
library i128;

use core::num::*;
use ::assert::assert;
use ::u128::U128;

/// The 128-bit signed integer type.
/// Represented as an underlying U128 value.
/// Actual value is underlying value minus 2 ^ 127
/// Max value is 2 ^ 127 - 1, min value is - 2 ^ 127
pub struct I128 {
underlying: U128,
}

pub trait From {
/// Function for creating I128 from U128
fn from(underlying: U128) -> Self;
}

impl From for I128 {
/// Helper function to get a signed number from with an underlying
fn from(underlying: U128) -> Self {
Self {
underlying
}
}
}

impl core::ops::Eq for I128 {
fn eq(self, other: Self) -> bool {
self.underlying == other.underlying
}
}

impl core::ops::Ord for I128 {
fn gt(self, other: Self) -> bool {
self.underlying > other.underlying
}

fn lt(self, other: Self) -> bool {
self.underlying < other.underlying
}
}

impl I128 {
/// The underlying value that corresponds to zero signed value
pub fn indent() -> U128 {
U128 {
upper: 1,
lower: 0,
}
}
}

impl I128 {
/// Initializes a new, zeroed I128.
pub fn new() -> Self {
Self {
underlying: ~Self::indent(),
}
}

/// The smallest value that can be represented by this integer type.
pub fn min() -> Self {
Self {
underlying: ~U128::min(),
}
}

/// The largest value that can be represented by this type,
pub fn max() -> Self {
Self {
underlying: ~U128::max(),
}
}

/// The size of this type in bits.
pub fn bits() -> u32 {
128
}

/// Helper function to get a negative value of unsigned number
pub fn neg_from(value: U128) -> Self {
Self {
underlying: ~Self::indent() - value,
}
}

/// Helper function to get a positive value from unsigned number
fn from_uint(value: U128) -> Self {
// as the minimal value of I128 is -~I128::indent() (1 << 63) we should add ~I128::indent() (1 << 63)
let underlying: U128 = value + ~Self::indent();
Self {
underlying
}
}
}

impl core::ops::Add for I128 {
/// Add a I128 to a I128. Panics on overflow.
fn add(self, other: Self) -> Self {
// subtract 1 << 63 to avoid double move
~Self::from(self.underlying - ~Self::indent() + other.underlying)
}
}

impl core::ops::Subtract for I128 {
/// Subtract a I128 from a I128. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = ~Self::new();
if self > other {
// add 1 << 63 to avoid loosing the move
res = ~Self::from(self.underlying - other.underlying + ~Self::indent());
} else {
// subtract from 1 << 63 as we are getting a negative value
res = ~Self::from(~Self::indent() - (other.underlying - self.underlying));
}
res
}
}

impl core::ops::Multiply for I128 {
/// Multiply a I128 with a I128. Panics of overflow.
fn multiply(self, other: Self) -> Self {
let mut res = ~Self::new();
if (self.underlying > ~Self::indent() || self.underlying == ~Self::indent()) && (other.underlying > ~Self::indent() || other.underlying == ~Self::indent()) {
res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying -~Self::indent()) + ~Self::indent());
} else if self.underlying < ~Self::indent() && other.underlying < ~Self::indent() {
res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent());
} else if (self.underlying > ~Self::indent() || self.underlying == ~Self::indent()) && other.underlying < ~Self::indent() {
res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying));
} else if self.underlying < ~Self::indent() && (other.underlying > ~Self::indent() || other.underlying == ~Self::indent()) {
res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying));
}
res
}
}

impl core::ops::Divide for I128 {
/// Divide a I128 by a I128. Panics if divisor is zero.
fn divide(self, divisor: Self) -> Self {
assert(divisor != ~Self::new());
let mut res = ~Self::new();
if (self.underlying > ~Self::indent() || self.underlying == ~Self::indent()) && divisor.underlying > ~Self::indent() {
res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent());
} else if self.underlying < ~Self::indent() && divisor.underlying < ~Self::indent() {
res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent());
} else if (self.underlying > ~Self::indent() || self.underlying == ~Self::indent()) && divisor.underlying < ~Self::indent() {
res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying));
} else if self.underlying < ~Self::indent() && divisor.underlying > ~Self::indent() {
res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent()));
}
res
}
}
151 changes: 151 additions & 0 deletions sway-lib-std/src/i16.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
library i16;

use core::num::*;
use ::assert::assert;

/// The 16-bit signed integer type.
/// Represented as an underlying u16 value.
/// Actual value is underlying value minus 2 ^ 15
/// Max value is 2 ^ 15 - 1, min value is - 2 ^ 15
pub struct I16 {
underlying: u16,
}

pub trait From {
/// Function for creating I16 from u16
fn from(underlying: u16) -> Self;
}

impl From for I16 {
/// Helper function to get a signed number from with an underlying
fn from(underlying: u16) -> Self {
Self {
underlying
}
}
}

impl core::ops::Eq for I16 {
fn eq(self, other: Self) -> bool {
self.underlying == other.underlying
}
}

impl core::ops::Ord for I16 {
fn gt(self, other: Self) -> bool {
self.underlying > other.underlying
}

fn lt(self, other: Self) -> bool {
self.underlying < other.underlying
}
}

impl I16 {
/// The underlying value that corresponds to zero signed value
pub fn indent() -> u16 {
32768u16
}
}

impl I16 {
/// Initializes a new, zeroed I16.
pub fn new() -> Self {
Self {
underlying: ~Self::indent(),
}
}

/// The smallest value that can be represented by this integer type.
pub fn min() -> Self {
Self {
underlying: ~u16::min(),
}
}

/// The largest value that can be represented by this type,
pub fn max() -> Self {
Self {
underlying: ~u16::max(),
}
}

/// The size of this type in bits.
pub fn bits() -> u32 {
16
}

/// Helper function to get a negative value of unsigned number
pub fn neg_from(value: u16) -> Self {
Self {
underlying: ~Self::indent() - value,
}
}

/// Helper function to get a positive value from unsigned number
fn from_uint(value: u16) -> Self {
// as the minimal value of I16 is -~I16::indent() (1 << 15) we should add ~I16::indent() (1 << 15)
let underlying: u16 = value + ~Self::indent();
Self {
underlying
}
}
}

impl core::ops::Add for I16 {
/// Add a I16 to a I16. Panics on overflow.
fn add(self, other: Self) -> Self {
// subtract 1 << 15 to avoid double move
~Self::from(self.underlying - ~Self::indent() + other.underlying)
}
}

impl core::ops::Subtract for I16 {
/// Subtract a I16 from a I16. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = ~Self::new();
if self > other {
// add 1 << 15 to avoid loosing the move
res = ~Self::from(self.underlying - other.underlying + ~Self::indent());
} else {
// subtract from 1 << 15 as we are getting a negative value
res = ~Self::from(~Self::indent() - (other.underlying - self.underlying));
}
res
}
}

impl core::ops::Multiply for I16 {
/// Multiply a I16 with a I16. Panics of overflow.
fn multiply(self, other: Self) -> Self {
let mut res = ~Self::new();
if self.underlying >= ~Self::indent() && other.underlying >= ~Self::indent() {
res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying -~Self::indent()) + ~Self::indent());
} else if self.underlying < ~Self::indent() && other.underlying < ~Self::indent() {
res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent());
} else if self.underlying >= ~Self::indent() && other.underlying < ~Self::indent() {
res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying));
} else if self.underlying < ~Self::indent() && other.underlying >= ~Self::indent() {
res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying));
}
res
}
}

impl core::ops::Divide for I16 {
/// Divide a I16 by a I16. Panics if divisor is zero.
fn divide(self, divisor: Self) -> Self {
assert(divisor != ~Self::new());
let mut res = ~Self::new();
if self.underlying >= ~Self::indent() && divisor.underlying > ~Self::indent() {
res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying -~Self::indent()) + ~Self::indent());
} else if self.underlying < ~Self::indent() && divisor.underlying < ~Self::indent() {
res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent());
} else if self.underlying >= ~Self::indent() && divisor.underlying < ~Self::indent() {
res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying));
} else if self.underlying < ~Self::indent() && divisor.underlying > ~Self::indent() {
res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent()));
}
res
}
}
Loading

0 comments on commit 283f196

Please sign in to comment.