balanced_ternary/
operations.rs1use crate::concepts::DigitOperate;
32use crate::{Digit, Ternary};
33use alloc::vec;
34use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub, Shl, Shr};
35
36impl Neg for &Ternary {
37 type Output = Ternary;
38
39 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 Shl<usize> for &Ternary {
147 type Output = Ternary;
148
149 fn shl(self, rhs: usize) -> Self::Output {
150 let mut repr = Ternary::new(vec![]);
151 repr.digits.extend(self.digits.iter().cloned());
152 repr.digits.extend(core::iter::repeat(Digit::Zero).take(rhs));
153 repr
154 }
155}
156
157impl Shr<usize> for &Ternary {
158 type Output = Ternary;
159
160 fn shr(self, rhs: usize) -> Self::Output {
161 if rhs >= self.digits.len() {
162 return Ternary::parse("0");
163 }
164 let len = self.digits.len() - rhs;
165 let mut repr = Ternary::new(self.digits[..len].to_vec());
166 if repr.digits.is_empty() {
167 repr.digits.push(Digit::Zero);
168 }
169 repr
170 }
171}
172
173impl Not for &Ternary {
174 type Output = Ternary;
175 fn not(self) -> Self::Output {
176 -self
177 }
178}
179
180#[cfg(test)]
181#[test]
182fn test_ternary_ops() {
183 use alloc::string::ToString;
184
185 let repr9 = Ternary::parse("+00");
186 let repr4 = Ternary::parse("++");
187 let repr13 = &repr9 + &repr4;
188 let repr17 = &repr13 + &repr4;
189 let repr34 = &repr17 + &repr17;
190
191 assert_eq!(repr13.to_string(), "+++");
192 assert_eq!(repr17.to_string(), "+-0-");
193 assert_eq!(repr34.to_string(), "++-+");
194
195 let repr30 = &repr34 - &repr4;
196 assert_eq!(repr30.to_dec(), 30);
197 assert_eq!(repr30.to_string(), "+0+0");
198
199 let repr120 = &repr30 * &repr4;
200 assert_eq!(repr120.to_dec(), 120);
201 assert_eq!(repr120.to_string(), "++++0");
202
203 let repr_neg120 = -&repr120;
204 assert_eq!(repr_neg120.to_dec(), -120);
205 assert_eq!(repr_neg120.to_string(), "----0");
206
207 let bitwise = &Ternary::parse("++00") & &Ternary::parse("0000");
208 assert_eq!(bitwise.to_string(), "0000");
209
210 let bitwise = &Ternary::parse("++00") & &Ternary::parse("0+00");
211 assert_eq!(bitwise.to_string(), "0+00");
212
213 let bitwise = &Ternary::parse("+000") | &Ternary::parse("000-");
214 assert_eq!(bitwise.to_string(), "+000");
215
216 let bitwise = &Ternary::parse("+000") & &Ternary::parse("000-");
217 assert_eq!(bitwise.to_string(), "000-");
218
219 let bitwise = &Ternary::parse("+000") | &Ternary::parse("000+");
220 assert_eq!(bitwise.to_string(), "+00+");
221}
222
223#[cfg(test)]
224#[test]
225fn test_shift_ops() {
226 use alloc::string::ToString;
227 let t = Ternary::parse("+0-");
228 assert_eq!((&t << 2).to_string(), "+0-00");
229 let back = &(&t << 2) >> 2;
230 assert_eq!(back.to_string(), "+0-");
231 let zero = &t >> 5;
232 assert_eq!(zero.to_string(), "0");
233}