Skip to content

Commit

Permalink
Refactor and turn lib.cairo back into scaffold
Browse files Browse the repository at this point in the history
  • Loading branch information
Nenad committed Jul 3, 2024
1 parent 01fd6d1 commit 1464a5b
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 113 deletions.
65 changes: 32 additions & 33 deletions exercises/practice/rational-numbers/.meta/example.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@ use core::fmt::{Debug, Formatter, Error};
#[derive(Drop, Debug, Copy)]
struct Rational {
numer: i128,
denom: i128,
denom: u128,
}

#[generate_trait]
impl RationalImpl of RationalTrait {
fn new(numer: i128, denom: i128) -> Rational {
assert!(denom != 0, "denominator cannot be 0");

let numer_sign: i128 = if (numer < 0 && denom > 0) || (numer > 0 && denom < 0) {
let sign: i128 = if (numer < 0 && denom > 0) || (numer > 0 && denom < 0) {
-1
} else {
1
};

let numer_abs = abs(numer);
let denom_abs = abs(denom);
let gcd_num = gcd_two_numbers(numer_abs, denom_abs);
let numer = abs(numer);
let denom = abs(denom);
let gcd_num = gcd_two_numbers(numer, denom);

let mut numer_minif = to_i128(numer_abs / gcd_num) * numer_sign;
let denom_minif = to_i128(denom_abs / gcd_num);
let numer = to_i128(numer / gcd_num) * sign;
let denom = denom / gcd_num;

Rational { numer: numer_minif, denom: denom_minif }
Rational { numer, denom }
}
}

Expand All @@ -43,14 +43,14 @@ impl RationalPartialEq of PartialEq<Rational> {

impl RationalNeg of Neg<Rational> {
fn neg(a: Rational) -> Rational {
RationalTrait::new(a.numer * -1, a.denom)
RationalTrait::new(a.numer * -1, to_i128(a.denom))
}
}

impl RationalAdd of Add<Rational> {
fn add(lhs: Rational, rhs: Rational) -> Rational {
let numer = (lhs.numer * rhs.denom) + (lhs.denom * rhs.numer);
let denom = lhs.denom * rhs.denom;
let numer = (lhs.numer * to_i128(rhs.denom)) + (to_i128(lhs.denom) * rhs.numer);
let denom = to_i128(lhs.denom * rhs.denom);
RationalTrait::new(numer, denom)
}
}
Expand All @@ -63,20 +63,20 @@ impl RationalSub of Sub<Rational> {

impl RationalMul of Mul<Rational> {
fn mul(lhs: Rational, rhs: Rational) -> Rational {
RationalTrait::new(lhs.numer * rhs.numer, lhs.denom * rhs.denom)
RationalTrait::new(lhs.numer * rhs.numer, to_i128(lhs.denom * rhs.denom))
}
}

impl RationalDiv of Div<Rational> {
fn div(lhs: Rational, rhs: Rational) -> Rational {
RationalTrait::new(lhs.numer * rhs.denom, lhs.denom * rhs.numer)
RationalTrait::new(lhs.numer * to_i128(rhs.denom), to_i128(lhs.denom) * rhs.numer)
}
}

#[generate_trait]
impl RationalAbs of RationalAbsTrait {
fn abs(self: @Rational) -> Rational {
RationalTrait::new(to_i128(abs(*self.numer)), *self.denom)
RationalTrait::new(to_i128(abs(*self.numer)), to_i128(*self.denom))
}
}

Expand All @@ -88,23 +88,20 @@ impl RationalPow of RationalPowTrait {
};
// fast_power works only with unsigned integers
let power_abs = abs(power);
let numer = abs(*self.numer);
let denom = to_u128(*self.denom);
// determine the new number's sign
let sign: i128 = if *self.numer < 0 && power_abs % 2 == 1 {
-1
} else {
1
};

let numer = to_i128(fast_power(abs(*self.numer), power_abs)) * sign;
let denom = to_i128(fast_power(*self.denom, power_abs));

if power < 0 {
RationalTrait::new(
sign * to_i128(fast_power(denom, power_abs)), to_i128(fast_power(numer, power_abs))
)
RationalTrait::new(denom, numer)
} else {
RationalTrait::new(
sign * to_i128(fast_power(numer, power_abs)), to_i128(fast_power(denom, power_abs))
)
RationalTrait::new(numer, denom)
}
}

Expand All @@ -114,7 +111,19 @@ impl RationalPow of RationalPowTrait {
if power.numer < 0 {
return 0;
};
fast_nr_optimize(fast_power(*self, to_u128(power.numer)), to_u128(power.denom), 30)
fast_nr_optimize(fast_power(*self, to_u128(power.numer)), power.denom, 30)
}
}

// Enables printing i128 values in tests.
// Note that this will soon be added to the core library.
impl I128Debug of Debug<i128> {
fn fmt(self: @i128, ref f: Formatter) -> Result<(), Error> {
if *self < 0 {
f.buffer.append(@"-");
};
f.buffer.append(@format!("{}", abs(*self)));
Result::Ok(())
}
}

Expand All @@ -135,15 +144,5 @@ fn to_u128(n: i128) -> u128 {
n.try_into().unwrap()
}

impl I128Debug of Debug<i128> {
fn fmt(self: @i128, ref f: Formatter) -> Result<(), Error> {
if *self < 0 {
f.buffer.append(@"-");
};
f.buffer.append(@format!("{}", abs(*self)));
Result::Ok(())
}
}

#[cfg(test)]
mod tests;
104 changes: 24 additions & 80 deletions exercises/practice/rational-numbers/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,140 +1,75 @@
use alexandria_math::gcd_of_n_numbers::gcd_two_numbers;
use alexandria_math::fast_power::fast_power;
use alexandria_math::fast_root::fast_nr_optimize;
use core::fmt::{Debug, Formatter, Error};

#[derive(Drop, Debug, Copy)]
struct Rational {
numer: i128,
denom: u128,
}
#[derive(Drop, Debug)]
struct Rational {}

#[generate_trait]
impl RationalImpl of RationalTrait {
fn new(numer: i128, denom: i128) -> Rational {
assert!(denom != 0, "denominator cannot be 0");

let sign: i128 = if (numer < 0 && denom > 0) || (numer > 0 && denom < 0) {
-1
} else {
1
};

let numer = abs(numer);
let denom = abs(denom);
let gcd_num = gcd_two_numbers(numer, denom);

let numer = to_i128(numer / gcd_num) * sign;
let denom = denom / gcd_num;

Rational { numer, denom }
panic!()
}
}

impl RationalPartialEq of PartialEq<Rational> {
fn eq(lhs: @Rational, rhs: @Rational) -> bool {
lhs.numer == rhs.numer && lhs.denom == rhs.denom
panic!()
}

fn ne(lhs: @Rational, rhs: @Rational) -> bool {
!(lhs == rhs)
panic!()
}
}

impl RationalNeg of Neg<Rational> {
fn neg(a: Rational) -> Rational {
RationalTrait::new(a.numer * -1, to_i128(a.denom))
panic!()
}
}

impl RationalAdd of Add<Rational> {
fn add(lhs: Rational, rhs: Rational) -> Rational {
let numer = (lhs.numer * to_i128(rhs.denom)) + (to_i128(lhs.denom) * rhs.numer);
let denom = to_i128(lhs.denom * rhs.denom);
RationalTrait::new(numer, denom)
panic!()
}
}

impl RationalSub of Sub<Rational> {
fn sub(lhs: Rational, rhs: Rational) -> Rational {
lhs + (-rhs)
panic!()
}
}

impl RationalMul of Mul<Rational> {
fn mul(lhs: Rational, rhs: Rational) -> Rational {
RationalTrait::new(lhs.numer * rhs.numer, to_i128(lhs.denom * rhs.denom))
panic!()
}
}

impl RationalDiv of Div<Rational> {
fn div(lhs: Rational, rhs: Rational) -> Rational {
RationalTrait::new(lhs.numer * to_i128(rhs.denom), to_i128(lhs.denom) * rhs.numer)
panic!()
}
}

#[generate_trait]
impl RationalAbs of RationalAbsTrait {
fn abs(self: @Rational) -> Rational {
RationalTrait::new(to_i128(abs(*self.numer)), to_i128(*self.denom))
panic!()
}
}

#[generate_trait]
impl RationalPow of RationalPowTrait {
fn pow(self: @Rational, power: i128) -> Rational {
if *self.numer == 0 {
return *self;
};
// fast_power works only with unsigned integers
let power_abs = abs(power);
let numer = abs(*self.numer);
let denom = *self.denom;
// determine the new number's sign
let sign: i128 = if *self.numer < 0 && power_abs % 2 == 1 {
-1
} else {
1
};

if power < 0 {
RationalTrait::new(
sign * to_i128(fast_power(denom, power_abs)), to_i128(fast_power(numer, power_abs))
)
} else {
RationalTrait::new(
sign * to_i128(fast_power(numer, power_abs)), to_i128(fast_power(denom, power_abs))
)
}
panic!()
}

fn rpow(self: @u128, power: Rational) -> u128 {
// Cairo does not support floating point numbers, so a negative rational number
// will always return the result 0 (as 1 divided by any number is 0 in Cairo)
if power.numer < 0 {
return 0;
};
fast_nr_optimize(fast_power(*self, to_u128(power.numer)), power.denom, 30)
panic!()
}
}

fn abs(n: i128) -> u128 {
let val = if n < 0 {
n * -1
} else {
n
};
to_u128(val)
}

fn to_i128(n: u128) -> i128 {
n.try_into().unwrap()
}

fn to_u128(n: i128) -> u128 {
n.try_into().unwrap()
}

// Enables printing i128 values in tests.
// Note that this will soon be added to the core library.
impl I128Debug of Debug<i128> {
fn fmt(self: @i128, ref f: Formatter) -> Result<(), Error> {
if *self < 0 {
Expand All @@ -145,5 +80,14 @@ impl I128Debug of Debug<i128> {
}
}

fn abs(n: i128) -> u128 {
let val = if n < 0 {
n * -1
} else {
n
};
val.try_into().unwrap()
}

#[cfg(test)]
mod tests;

0 comments on commit 1464a5b

Please sign in to comment.