balanced_ternary/
operations.rs

1//! This module provides implementations for arithmetic operations on the `Ternary` type
2//! such as addition, subtraction, multiplication, and division.
3//! Using `Ternary` arithmetic:
4//!
5//! ```rust
6//! use balanced_ternary::Ternary;
7//!
8//! let repr9 = Ternary::parse("+00"); // Represents decimal 9 in balanced ternary
9//! let repr4 = Ternary::parse("++");  // Represents decimal 4 in balanced ternary
10//! let sum = &repr9 + &repr4;         // Results in Ternary::parse("+++"), decimal 13
11//! assert_eq!(sum.to_dec(), 13);
12//! let difference = &sum - &repr4;   // Results in Ternary::parse("+00"), decimal 9
13//! assert_eq!(difference.to_dec(), 9);
14//! ```
15//!
16//! # Implementations
17//!
18//! The following arithmetic operations are implemented for the `Ternary` :
19//!
20//! ## `Ternary` type
21//!
22//! - `Neg` and `Not` for `&Ternary`: Negates the `Ternary` by negating each digit in its balanced ternary representation.
23//! - `Add<&Ternary>` for `&Ternary`: Adds two `Ternary` values and returns a new `Ternary`. Panics on overflow.
24//! - `Sub<&Ternary>` for `&Ternary`: Subtracts one `Ternary` from another and returns a new `Ternary`. Panics on overflow.
25//! - `Mul<&Ternary>` for `&Ternary`: Multiplies two `Ternary` values and returns a new `Ternary`. Panics on overflow.
26//! - `Div<&Ternary>` for `&Ternary`: Divides one `Ternary` by another and returns a new `Ternary`. Panics on overflow or division by zero.
27//! - `BitAnd<&Ternary>` for `&Ternary`: Computes the bitwise AND operation on two `Ternary` operands.
28//! - `BitOr<&Ternary>` for `&Ternary`: Computes the bitwise OR operation on two `Ternary` operands.
29//! - `BitXor<&Ternary>` for `&Ternary`: Computes the bitwise XOR operation on two `Ternary` operands.
30
31use crate::{Digit, Ternary};
32use alloc::vec;
33use alloc::vec::Vec;
34use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
35
36impl Neg for &Ternary {
37    type Output = Ternary;
38
39    /// Returns the negation of the current `Ternary` object.
40    ///
41    /// Negates each digit in the number.
42    fn neg(self) -> Self::Output {
43        let mut repr = Ternary::new(vec![]);
44        for digit in self.digits.iter() {
45            repr.digits.push(-*digit);
46        }
47        repr
48    }
49}
50
51impl Add<&Ternary> for &Ternary {
52    type Output = Ternary;
53
54    fn add(self, rhs: &Ternary) -> Self::Output {
55        Ternary::from_dec(
56            self.to_dec()
57                .checked_add(rhs.to_dec())
58                .expect("Overflow in addition."),
59        )
60    }
61}
62
63impl Sub<&Ternary> for &Ternary {
64    type Output = Ternary;
65
66    fn sub(self, rhs: &Ternary) -> Self::Output {
67        Ternary::from_dec(
68            self.to_dec()
69                .checked_sub(rhs.to_dec())
70                .expect("Overflow in subtraction."),
71        )
72    }
73}
74
75impl Mul<&Ternary> for &Ternary {
76    type Output = Ternary;
77
78    fn mul(self, rhs: &Ternary) -> Self::Output {
79        Ternary::from_dec(
80            self.to_dec()
81                .checked_mul(rhs.to_dec())
82                .expect("Overflow in multiplication."),
83        )
84    }
85}
86
87impl Div<&Ternary> for &Ternary {
88    type Output = Ternary;
89
90    fn div(self, rhs: &Ternary) -> Self::Output {
91        Ternary::from_dec(
92            self.to_dec()
93                .checked_div(rhs.to_dec())
94                .expect("Overflow in division or division by zero."),
95        )
96    }
97}
98
99impl BitAnd<&Ternary> for &Ternary {
100    type Output = Ternary;
101
102    fn bitand(self, rhs: &Ternary) -> Self::Output {
103        if self.log() < rhs.log() {
104            return rhs & self;
105        }
106        let mut digits = Vec::new();
107        for (i, d) in self.digits.iter().rev().enumerate() {
108            let other = rhs.get_digit(i).unwrap_or(&Digit::Zero);
109            digits.push(*d & *other);
110        }
111        digits.reverse();
112        Ternary::new(digits)
113    }
114}
115
116impl BitOr<&Ternary> for &Ternary {
117    type Output = Ternary;
118
119    fn bitor(self, rhs: &Ternary) -> Self::Output {
120        if self.log() < rhs.log() {
121            return rhs | self;
122        }
123        let mut digits = Vec::new();
124        for (i, d) in self.digits.iter().rev().enumerate() {
125            let other = rhs.get_digit(i).unwrap_or(&Digit::Zero);
126            digits.push(*d | *other);
127        }
128        digits.reverse();
129        Ternary::new(digits)
130    }
131}
132
133impl BitXor<&Ternary> for &Ternary {
134    type Output = Ternary;
135
136    fn bitxor(self, rhs: &Ternary) -> Self::Output {
137        if self.log() < rhs.log() {
138            return rhs ^ self;
139        }
140        let mut digits = Vec::new();
141        for (i, d) in self.digits.iter().rev().enumerate() {
142            let other = rhs.get_digit(i).unwrap_or(&Digit::Zero);
143            digits.push(*d ^ *other);
144        }
145        digits.reverse();
146        Ternary::new(digits)
147    }
148}
149
150impl Not for &Ternary {
151    type Output = Ternary;
152    fn not(self) -> Self::Output {
153        -self
154    }
155}
156
157#[cfg(test)]
158#[test]
159fn test_ternary_ops() {
160    use alloc::string::ToString;
161
162    let repr9 = Ternary::parse("+00");
163    let repr4 = Ternary::parse("++");
164    let repr13 = &repr9 + &repr4;
165    let repr17 = &repr13 + &repr4;
166    let repr34 = &repr17 + &repr17;
167
168    assert_eq!(repr13.to_string(), "+++");
169    assert_eq!(repr17.to_string(), "+-0-");
170    assert_eq!(repr34.to_string(), "++-+");
171
172    let repr30 = &repr34 - &repr4;
173    assert_eq!(repr30.to_dec(), 30);
174    assert_eq!(repr30.to_string(), "+0+0");
175
176    let repr120 = &repr30 * &repr4;
177    assert_eq!(repr120.to_dec(), 120);
178    assert_eq!(repr120.to_string(), "++++0");
179
180    let repr_neg120 = -&repr120;
181    assert_eq!(repr_neg120.to_dec(), -120);
182    assert_eq!(repr_neg120.to_string(), "----0");
183
184    let bitwise = &Ternary::parse("++00") & &Ternary::parse("0000");
185    assert_eq!(bitwise.to_string(), "0000");
186
187    let bitwise = &Ternary::parse("++00") & &Ternary::parse("0+00");
188    assert_eq!(bitwise.to_string(), "0+00");
189
190    let bitwise = &Ternary::parse("+000") | &Ternary::parse("000-");
191    assert_eq!(bitwise.to_string(), "+000");
192
193    let bitwise = &Ternary::parse("+000") & &Ternary::parse("000-");
194    assert_eq!(bitwise.to_string(), "000-");
195
196    let bitwise = &Ternary::parse("+000") | &Ternary::parse("000+");
197    assert_eq!(bitwise.to_string(), "+00+");
198}