balanced_ternary/
operations.rs1use 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 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}