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::concepts::DigitOperate;
32use crate::{Digit, Ternary};
33use alloc::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 Add<Digit> for &Ternary {
64    type Output = Ternary;
65
66    fn add(self, rhs: Digit) -> Self::Output {
67        Ternary::from_dec(
68            self.to_dec()
69                .checked_add(rhs.to_i8() as i64)
70                .expect("Overflow in addition."),
71        )
72    }
73}
74
75impl Sub<&Ternary> for &Ternary {
76    type Output = Ternary;
77
78    fn sub(self, rhs: &Ternary) -> Self::Output {
79        Ternary::from_dec(
80            self.to_dec()
81                .checked_sub(rhs.to_dec())
82                .expect("Overflow in subtraction."),
83        )
84    }
85}
86
87impl Sub<Digit> for &Ternary {
88    type Output = Ternary;
89    fn sub(self, rhs: Digit) -> Self::Output {
90        Ternary::from_dec(
91            self.to_dec()
92                .checked_sub(rhs.to_i8() as i64)
93                .expect("Overflow in subtraction."),
94        )
95    }
96}
97
98impl Mul<&Ternary> for &Ternary {
99    type Output = Ternary;
100
101    fn mul(self, rhs: &Ternary) -> Self::Output {
102        Ternary::from_dec(
103            self.to_dec()
104                .checked_mul(rhs.to_dec())
105                .expect("Overflow in multiplication."),
106        )
107    }
108}
109
110impl Div<&Ternary> for &Ternary {
111    type Output = Ternary;
112
113    fn div(self, rhs: &Ternary) -> Self::Output {
114        Ternary::from_dec(
115            self.to_dec()
116                .checked_div(rhs.to_dec())
117                .expect("Overflow in division or division by zero."),
118        )
119    }
120}
121
122impl BitAnd<&Ternary> for &Ternary {
123    type Output = Ternary;
124
125    fn bitand(self, rhs: &Ternary) -> Self::Output {
126        self.each_zip(Digit::bitand, rhs.clone())
127    }
128}
129
130impl BitOr<&Ternary> for &Ternary {
131    type Output = Ternary;
132
133    fn bitor(self, rhs: &Ternary) -> Self::Output {
134        self.each_zip(Digit::bitor, rhs.clone())
135    }
136}
137
138impl BitXor<&Ternary> for &Ternary {
139    type Output = Ternary;
140
141    fn bitxor(self, rhs: &Ternary) -> Self::Output {
142        self.each_zip(Digit::bitxor, rhs.clone())
143    }
144}
145
146impl Not for &Ternary {
147    type Output = Ternary;
148    fn not(self) -> Self::Output {
149        -self
150    }
151}
152
153#[cfg(test)]
154#[test]
155fn test_ternary_ops() {
156    use alloc::string::ToString;
157
158    let repr9 = Ternary::parse("+00");
159    let repr4 = Ternary::parse("++");
160    let repr13 = &repr9 + &repr4;
161    let repr17 = &repr13 + &repr4;
162    let repr34 = &repr17 + &repr17;
163
164    assert_eq!(repr13.to_string(), "+++");
165    assert_eq!(repr17.to_string(), "+-0-");
166    assert_eq!(repr34.to_string(), "++-+");
167
168    let repr30 = &repr34 - &repr4;
169    assert_eq!(repr30.to_dec(), 30);
170    assert_eq!(repr30.to_string(), "+0+0");
171
172    let repr120 = &repr30 * &repr4;
173    assert_eq!(repr120.to_dec(), 120);
174    assert_eq!(repr120.to_string(), "++++0");
175
176    let repr_neg120 = -&repr120;
177    assert_eq!(repr_neg120.to_dec(), -120);
178    assert_eq!(repr_neg120.to_string(), "----0");
179
180    let bitwise = &Ternary::parse("++00") & &Ternary::parse("0000");
181    assert_eq!(bitwise.to_string(), "0000");
182
183    let bitwise = &Ternary::parse("++00") & &Ternary::parse("0+00");
184    assert_eq!(bitwise.to_string(), "0+00");
185
186    let bitwise = &Ternary::parse("+000") | &Ternary::parse("000-");
187    assert_eq!(bitwise.to_string(), "+000");
188
189    let bitwise = &Ternary::parse("+000") & &Ternary::parse("000-");
190    assert_eq!(bitwise.to_string(), "000-");
191
192    let bitwise = &Ternary::parse("+000") | &Ternary::parse("000+");
193    assert_eq!(bitwise.to_string(), "+00+");
194}