Jaime López
Data Product Developer
Centereach, NY

Sections:

Profiles:

Naive implementation of fractions in Rust

In this note arithmetic operations for fractions are implemented using Rust language. A two term structure is defined to represent numerator and denominator.

struct Frac {
    a: i32,  // numerator
    b: i32,  // denominator
}

With this structure, we are able to define fractions like the following examples:

let x = Frac{a: 6, b: 3};
let y = Frac{a: 2, b: 5};
println!("x = {}/{}", x.a, x.b);
println!("y = {}/{}", y.a, y.b);

A basic function that is required for fraction-arithmetic is one to find the greather commond denominator, as a way to represent fractions where numerator and denominator are simpler.

fn gcd(a: i32, b: i32) -> i32 {
    if b == 0 { return a; }
    let mut x = a;
    let mut y = b;
    if b > a {
        let z = x;
        x = y;
        y = z;
    }
    return gcd(y, x % y);
}

Operations are defined inside a impl Frac { } block, as follows:

// Sum operation
fn sum(&self, f: &Frac) -> Frac {
    let num = &self.a * f.b + &self.b * f.a;
    let den = &self.b * f.b;
    return Frac{a: num, b: den}.reduce();
}
// Substract operation
fn sub(&self, f: &Frac) -> Frac {
    let num = &self.a * f.b - &self.b * f.a;
    let den = &self.b * f.b;
    return Frac{a: num, b: den}.reduce();
}
// Multiplication
fn mul(&self, f: &Frac) -> Frac {
    let num = &self.a * f.a;
    let den = &self.b * f.b;
    return Frac{a: num, b: den}.reduce();
}
// Division
fn div(&self, f: &Frac) -> Frac {
    let num = &self.a * &f.b;
    let den = &self.b * &f.a;
    return Frac{a: num, b: den}.reduce();
}

The reduce function called in every operation is the ones that uses gcd function to simplify a fraction:

fn reduce(&self) -> Frac {
    let cd = gcd(self.a, self.b);
    return Frac{a: &self.a / cd, b: &self.b / cd};
}

Here is the full program list:

// Arithmentic on fractions naive implementation

// A basic structure to represent fractions
struct Frac {
    a: i32,  // numerator
    b: i32,  // denominator
}

impl Frac {
    // Sum operation
    fn sum(&self, f: &Frac) -> Frac {
        let num = &self.a * f.b + &self.b * f.a;
        let den = &self.b * f.b;
        return Frac{a: num, b: den}.reduce();
    }
    // Substract operation
    fn sub(&self, f: &Frac) -> Frac {
        let num = &self.a * f.b - &self.b * f.a;
        let den = &self.b * f.b;
        return Frac{a: num, b: den}.reduce();
    }
    // Multiplication
    fn mul(&self, f: &Frac) -> Frac {
        let num = &self.a * f.a;
        let den = &self.b * f.b;
        return Frac{a: num, b: den}.reduce();
    }
    // Division
    fn div(&self, f: &Frac) -> Frac {
        let num = &self.a * &f.b;
        let den = &self.b * &f.a;
        return Frac{a: num, b: den}.reduce();
    }
    // Reduce fraction with gcd
    fn reduce(&self) -> Frac {
        let cd = gcd(self.a, self.b);
        return Frac{a: &self.a / cd, b: &self.b / cd};
    }
}

// Greather Common Divisor
fn gcd(a: i32, b: i32) -> i32 {
    if b == 0 { return a; }
    let mut x = a;
    let mut y = b;
    if b > a {
        let z = x;
        x = y;
        y = z;
    }
    return gcd(y, x % y);
}

fn main() {
    // Two fractions to use as examples
    let x = Frac{a: 6, b: 3};
    let y = Frac{a: 2, b: 5};
    println!("x = {}/{}", x.a, x.b);
    println!("y = {}/{}", y.a, y.b);

    // Operating over them
    let r_sum = x.sum(&y);
    let r_sub = x.sub(&y);
    let r_mul = x.mul(&y);
    let r_div = x.div(&y);
    // Displaying results
    println!("x + y = {}/{}", r_sum.a, r_sum.b);
    println!("x - y = {}/{}", r_sub.a, r_sub.b);
    println!("x * y = {}/{}", r_mul.a, r_mul.b);
    println!("x / y = {}/{}", r_div.a, r_div.b);
}

The output of this program is:

x = 6/3
y = 2/5
x + y = 12/5
x - y = 8/5
x * y = 4/5
x / y = 5/1

Date: Dec. 29, 2023