balanced_ternary/digit.rs
1//! ## Module: Balanced Ternary `Digit`
2//!
3//! This module defines the `Digit` type for the balanced ternary numeral system,
4//! along with its associated operations and functionality.
5//!
6//! ### Key Features
7//!
8//! - **`Digit` Type**: Represents a digit in the balanced ternary numeral system.
9//! - Possible values: `Neg` (-1), `Zero` (0), `Pos` (+1).
10//! - Provides utility functions for converting between characters, integers, and other formats.
11//! - **Arithmetic Operators**: Implements arithmetic operations for digits, including:
12//! - Negation (`Neg`) and Bitwise Not (`Not`).
13//! - Addition (`Add`) and Subtraction (`Sub`).
14//! - Multiplication (`Mul`) and Division (`Div`), with safe handling of divisors (division by zero panics).
15//! - **Logical Operators**: Supports bitwise logical operations (AND, OR, XOR) based on ternary logic rules.
16//! - **Custom Methods**: Additional utility methods implementing balanced ternary logic principles.
17//!
18//! ### Supported Use Cases
19//!
20//! - Arithmetic in balanced ternary numeral systems.
21//! - Logic operations in custom numeral systems.
22//! - Conversion between balanced ternary representation and more common formats like integers and characters.
23//!
24//! ## `Digit` type arithmetical and logical operations
25//!
26//! - `Neg` and `Not` for `Digit`: Negates the digit value, adhering to balanced ternary rules.
27//! - `Add<Digit>` for `Digit`: Adds two `Digit` values and returns a `Ternary`.
28//! - `Sub<Digit>` for `Digit`: Subtracts one `Digit` from another and returns a `Ternary`.
29//! - `Mul<Digit>` for `Digit`: Multiplies two `Digit` values and returns a `Digit`.
30//! - `Div<Digit>` for `Digit`: Divides one `Digit` by another and returns a `Digit`. Division by zero panics.
31//!
32//! ### Logical Operations for `Digit`
33//!
34//! The `Digit` type supports bitwise logical operations, which are implemented according to logical rules applicable to balanced ternary digits.
35//!
36//! ### Digits operations
37//!
38//! #### Unary operations
39//!
40//! These operations (except inc & dec) can be applied for `Ternary` with `Ternary::each(operator)`:
41//!
42//! | Unary operations | - | 0 | + |
43//! |-----------------------|---|---|---|
44//! | possibly | - | + | + |
45//! | necessary | - | - | + |
46//! | contingently | - | + | - |
47//! | ht_not | + | - | - |
48//! | post | 0 | + | - |
49//! | pre | + | - | 0 |
50//! | `!` (not) / `-` (neg) | + | 0 | - |
51//! | absolute_positive | + | 0 | + |
52//! | positive | 0 | 0 | + |
53//! | not_negative | 0 | + | + |
54//! | not_positive | - | - | 0 |
55//! | negative | - | 0 | 0 |
56//! | absolute_negative | - | 0 | - |
57//! | inc | 0 | + | `+-` |
58//! | dec | `-+` | - | 0 |
59//!
60//! `inc` and `dec` can respectively be replaced by `post` and `pre` which are the same operations without the carry digit.
61//!
62//! #### Binary operations
63//!
64//! These operations (except add & sub) can be applied for `Ternary` with:
65//!
66//! - `Ternary::each_with(operator, with)`, or,
67//! - `Ternary::each_zip(operator, other)`:
68//!
69//! | Binary operations | -<br>- | -<br>0 | -<br>+ | 0<br>- | 0<br>0 | 0<br>+ | +<br>- | +<br>0 | +<br>+ |
70//! |------------------|--------|--------|--------|--------|--------|--------|--------|--------|--------|
71//! | `+` (add) | -+ | - | 0 | - | 0 | + | 0 | + | +- |
72//! | `-` (sub) | 0 | - | -+ | + | 0 | - | +- | + | 0 |
73//! | `/` (div) | + | | - | 0 | | 0 | - | | + |
74//! | `*` (mul) | + | 0 | - | 0 | 0 | 0 | - | 0 | + |
75//! | `&` (bitand) | - | - | - | - | 0 | 0 | - | 0 | + |
76//! | bi3_and | - | 0 | - | 0 | 0 | 0 | - | 0 | + |
77//! | `\|` (bitor) | - | 0 | + | 0 | 0 | + | + | + | + |
78//! | bi3_or | - | 0 | + | 0 | 0 | 0 | + | 0 | + |
79//! | `^` (bitxor) | - | 0 | + | 0 | 0 | 0 | + | 0 | - |
80//! | k3_equiv | + | 0 | - | 0 | 0 | 0 | - | 0 | + |
81//! | k3_imply | + | + | + | 0 | 0 | + | - | 0 | + |
82//! | bi3_imply | + | 0 | + | 0 | 0 | 0 | - | 0 | + |
83//! | l3_imply | + | + | + | 0 | + | + | - | 0 | + |
84//! | rm3_imply | + | + | + | - | 0 | + | - | - | + |
85//! | para_imply | + | + | + | - | 0 | + | - | 0 | + |
86//! | ht_imply | + | + | + | - | + | + | - | 0 | + |
87//!
88//! `/`, `*`, `&`, `|` and `^` should not be used with `Ternary::each_{with,zip}()`.
89//! Instead, use these operators from `Ternary` directly.
90//!
91//! Do so to `add` and `sub` ternaries, too.
92//!
93
94use crate::Ternary;
95use alloc::vec;
96use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
97
98/// Represents a digit in the balanced ternary numeral system.
99///
100/// A digit can have one of three values:
101/// - `Neg` (-1): Represents the value -1 in the balanced ternary system.
102/// - `Zero` (0): Represents the value 0 in the balanced ternary system.
103/// - `Pos` (+1): Represents the value +1 in the balanced ternary system.
104///
105/// Provides utility functions for converting to/from characters, integers, and negation.
106#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
107pub enum Digit {
108 /// Represents -1
109 Neg,
110 /// Represents 0
111 Zero,
112 /// Represents +1
113 Pos,
114}
115
116impl Digit {
117 /// Converts the `Digit` into its character representation.
118 ///
119 /// - Returns:
120 /// - `-` for `Digit::Neg`
121 /// - `0` for `Digit::Zero`
122 /// - `+` for `Digit::Pos`
123 pub const fn to_char(&self) -> char {
124 match self {
125 Digit::Neg => '-',
126 Digit::Zero => '0',
127 Digit::Pos => '+',
128 }
129 }
130
131 /// Creates a `Digit` from its character representation.
132 ///
133 /// - Accepts:
134 /// - `-` for `Digit::Neg`
135 /// - `0` for `Digit::Zero`
136 /// - `+` for `Digit::Pos`
137 /// - Panics if the input character is invalid.
138 pub const fn from_char(c: char) -> Digit {
139 match c {
140 '-' => Digit::Neg,
141 '0' => Digit::Zero,
142 '+' => Digit::Pos,
143 _ => panic!("Invalid value. A Ternary must be either -, 0 or +."),
144 }
145 }
146
147 /// Converts the `Digit` into its integer representation.
148 ///
149 /// - Returns:
150 /// - -1 for `Digit::Neg`
151 /// - 0 for `Digit::Zero`
152 /// - 1 for `Digit::Pos`
153 pub const fn to_i8(&self) -> i8 {
154 match self {
155 Digit::Neg => -1,
156 Digit::Zero => 0,
157 Digit::Pos => 1,
158 }
159 }
160
161 /// Creates a `Digit` from its integer representation.
162 ///
163 /// - Accepts:
164 /// - -1 for `Digit::Neg`
165 /// - 0 for `Digit::Zero`
166 /// - 1 for `Digit::Pos`
167 /// - Panics if the input integer is invalid.
168 pub const fn from_i8(i: i8) -> Digit {
169 match i {
170 -1 => Digit::Neg,
171 0 => Digit::Zero,
172 1 => Digit::Pos,
173 _ => panic!("Invalid value. A Ternary must be either -1, 0 or +1."),
174 }
175 }
176
177 /// Returns the corresponding possible value of the current `Digit`.
178 ///
179 /// - Returns:
180 /// - `Digit::Neg` for `Digit::Neg`
181 /// - `Digit::Pos` for `Digit::Zero`
182 /// - `Digit::Pos` for `Digit::Pos`
183 pub const fn possibly(self) -> Self {
184 match self {
185 Digit::Neg => Digit::Neg,
186 Digit::Zero => Digit::Pos,
187 Digit::Pos => Digit::Pos,
188 }
189 }
190
191 /// Determines the condition of necessity for the current `Digit`.
192 ///
193 /// - Returns:
194 /// - `Digit::Neg` for `Digit::Neg`
195 /// - `Digit::Neg` for `Digit::Zero`
196 /// - `Digit::Pos` for `Digit::Pos`
197 ///
198 /// This method is used to calculate necessity as part
199 /// of balanced ternary logic systems.
200 pub const fn necessary(self) -> Self {
201 match self {
202 Digit::Neg => Digit::Neg,
203 Digit::Zero => Digit::Neg,
204 Digit::Pos => Digit::Pos,
205 }
206 }
207
208 /// Determines the condition of contingency for the current `Digit`.
209 ///
210 /// - Returns:
211 /// - `Digit::Neg` for `Digit::Neg`
212 /// - `Digit::Pos` for `Digit::Zero`
213 /// - `Digit::Neg` for `Digit::Pos`
214 ///
215 /// This method represents contingency in balanced ternary logic,
216 /// which defines the specific alternation of `Digit` values.
217 pub const fn contingently(self) -> Self {
218 match self {
219 Digit::Neg => Digit::Neg,
220 Digit::Zero => Digit::Pos,
221 Digit::Pos => Digit::Neg,
222 }
223 }
224
225 /// Returns the absolute positive value of the current `Digit`.
226 ///
227 /// - Returns:
228 /// - `Digit::Pos` for `Digit::Neg`
229 /// - `Digit::Zero` for `Digit::Zero`
230 /// - `Digit::Pos` for `Digit::Pos`
231 pub const fn absolute_positive(self) -> Self {
232 match self {
233 Digit::Neg => Digit::Pos,
234 Digit::Zero => Digit::Zero,
235 Digit::Pos => Digit::Pos,
236 }
237 }
238
239 /// Determines the strictly positive condition for the current `Digit`.
240 ///
241 /// - Returns:
242 /// - `Digit::Zero` for `Digit::Neg`
243 /// - `Digit::Zero` for `Digit::Zero`
244 /// - `Digit::Pos` for `Digit::Pos`
245 ///
246 /// This method is used to calculate strictly positive states
247 /// in association with ternary logic.
248 pub const fn positive(self) -> Self {
249 match self {
250 Digit::Neg => Digit::Zero,
251 Digit::Zero => Digit::Zero,
252 Digit::Pos => Digit::Pos,
253 }
254 }
255
256 /// Determines the condition of non-negativity for the current `Digit`.
257 ///
258 /// - Returns:
259 /// - `Digit::Zero` for `Digit::Neg`
260 /// - `Digit::Pos` for `Digit::Zero`
261 /// - `Digit::Pos` for `Digit::Pos`
262 ///
263 /// This method is used to filter out negative conditions
264 /// in computations with balanced ternary representations.
265 pub const fn not_negative(self) -> Self {
266 match self {
267 Digit::Neg => Digit::Zero,
268 Digit::Zero => Digit::Pos,
269 Digit::Pos => Digit::Pos,
270 }
271 }
272
273 /// Determines the condition of non-positivity for the current `Digit`.
274 ///
275 /// - Returns:
276 /// - `Digit::Neg` for `Digit::Neg`
277 /// - `Digit::Neg` for `Digit::Zero`
278 /// - `Digit::Zero` for `Digit::Pos`
279 ///
280 /// This method complements the `positive` condition and captures
281 /// states that are not strictly positive.
282 pub const fn not_positive(self) -> Self {
283 match self {
284 Digit::Neg => Digit::Neg,
285 Digit::Zero => Digit::Neg,
286 Digit::Pos => Digit::Zero,
287 }
288 }
289
290 /// Determines the strictly negative condition for the current `Digit`.
291 ///
292 /// - Returns:
293 /// - `Digit::Neg` for `Digit::Neg`
294 /// - `Digit::Zero` for `Digit::Zero`
295 /// - `Digit::Zero` for `Digit::Pos`
296 ///
297 /// This method calculates strictly negative states
298 /// in association with ternary logic.
299 pub const fn negative(self) -> Self {
300 match self {
301 Digit::Neg => Digit::Neg,
302 Digit::Zero => Digit::Zero,
303 Digit::Pos => Digit::Zero,
304 }
305 }
306
307 /// Returns the absolute negative value of the current `Digit`.
308 ///
309 /// - Returns:
310 /// - `Digit::Neg` for `Digit::Neg`
311 /// - `Digit::Zero` for `Digit::Zero`
312 /// - `Digit::Neg` for `Digit::Pos`
313 pub const fn absolute_negative(self) -> Self {
314 match self {
315 Digit::Neg => Digit::Neg,
316 Digit::Zero => Digit::Zero,
317 Digit::Pos => Digit::Neg,
318 }
319 }
320
321 /// Performs Kleene implication with the current `Digit` as `self` and another `Digit`.
322 ///
323 /// - `self`: The antecedent of the implication.
324 /// - `other`: The consequent of the implication.
325 ///
326 /// - Returns:
327 /// - `Digit::Pos` when `self` is `Digit::Neg`.
328 /// - The positive condition of `other` when `self` is `Digit::Zero`.
329 /// - `other` when `self` is `Digit::Pos`.
330 ///
331 /// Implements Kleene ternary implication logic, which includes
332 /// determining the logical result based on antecedent and consequent.
333 pub const fn k3_imply(self, other: Self) -> Self {
334 match self {
335 Digit::Neg => Digit::Pos,
336 Digit::Zero => other.positive(),
337 Digit::Pos => other,
338 }
339 }
340
341 /// Apply a ternary equivalence operation for the current `Digit` and another `Digit`.
342 ///
343 /// - `self`: The first operand of the equivalence operation.
344 /// - `other`: The second operand of the equivalence operation.
345 ///
346 /// - Returns:
347 /// - The negation of `other` when `self` is `Digit::Neg`.
348 /// - `Digit::Zero` when `self` is `Digit::Zero`.
349 /// - `other` when `self` is `Digit::Pos`.
350 ///
351 /// This method implements a ternary logic equivalence, which captures the relationship between
352 /// two balanced ternary `Digit`s based on their logical equivalence.
353 pub const fn k3_equiv(self, other: Self) -> Self {
354 match self {
355 Digit::Neg => match other {
356 Digit::Neg => Digit::Pos,
357 Digit::Zero => Digit::Zero,
358 Digit::Pos => Digit::Neg,
359 },
360 Digit::Zero => Digit::Zero,
361 Digit::Pos => other,
362 }
363 }
364
365 /// Performs a ternary AND operation for the current `Digit` and another `Digit`.
366 ///
367 /// - `self`: The first operand of the AND operation.
368 /// - `other`: The second operand of the AND operation.
369 ///
370 /// - Returns:
371 /// - `Digit::Neg` if `self` is `Digit::Neg` and `other` is not `Digit::Zero`.
372 /// - `Digit::Zero` if either `self` or `other` is `Digit::Zero`.
373 /// - `other` if `self` is `Digit::Pos`.
374 ///
375 /// This method implements Bochvar's internal three-valued logic in balanced ternary AND operation,
376 /// which evaluates the logical conjunction of two `Digit`s in the ternary logic system.
377 pub const fn bi3_and(self, other: Self) -> Self {
378 match self {
379 Digit::Neg => other.absolute_negative(),
380 Digit::Zero => Digit::Zero,
381 Digit::Pos => other,
382 }
383 }
384
385 /// Performs a ternary OR operation for the current `Digit` and another `Digit`.
386 ///
387 /// - `self`: The first operand of the OR operation.
388 /// - `other`: The second operand of the OR operation.
389 ///
390 /// - Returns:
391 /// - `other` if `self` is `Digit::Neg`.
392 /// - `Digit::Zero` if `self` is `Digit::Zero`.
393 /// - `Digit::Pos` if `self` is `Digit::Pos` and `other` is not `Digit::Zero`.
394 ///
395 /// This method implements Bochvar's three-valued internal ternary logic for the OR operation,
396 /// determining the logical disjunction of two balanced ternary `Digit`s.
397 pub const fn bi3_or(self, other: Self) -> Self {
398 match self {
399 Digit::Neg => other,
400 Digit::Zero => Digit::Zero,
401 Digit::Pos => other.absolute_positive(),
402 }
403 }
404
405 /// Performs Bochvar's internal three-valued implication with the current `Digit` as `self`
406 /// and another `Digit` as the consequent.
407 ///
408 /// - `self`: The antecedent of the implication.
409 /// - `other`: The consequent of the implication.
410 ///
411 /// - Returns:
412 /// - `Digit::Zero` if `self` is `Digit::Neg` and `other` is `Digit::Zero`.
413 /// - `Digit::Pos` if `self` is `Digit::Neg` and `other` is not `Digit::Zero`.
414 /// - `Digit::Zero` if `self` is `Digit::Zero`.
415 /// - `other` if `self` is `Digit::Pos`.
416 ///
417 /// This method implements Bochvar's internal implication logic, which evaluates
418 /// the logical consequence, between two balanced ternary `Digit`s in a manner
419 /// consistent with three-valued logic principles.
420 pub const fn bi3_imply(self, other: Self) -> Self {
421 match self {
422 Digit::Neg => other.absolute_positive(),
423 Digit::Zero => Digit::Zero,
424 Digit::Pos => other,
425 }
426 }
427
428 /// Performs Łukasiewicz implication with the current `Digit` as `self` and another `Digit`.
429 ///
430 /// - `self`: The antecedent of the implication.
431 /// - `other`: The consequent of the implication.
432 ///
433 /// - Returns:
434 /// - `Digit::Pos` when `self` is `Digit::Neg`.
435 /// - The non-negative condition of `other` when `self` is `Digit::Zero`.
436 /// - `other` when `self` is `Digit::Pos`.
437 ///
438 /// Implements Łukasiewicz ternary implication logic, which
439 /// evaluates an alternative approach for implication compared to Kleene logic.
440 pub const fn l3_imply(self, other: Self) -> Self {
441 match self {
442 Digit::Neg => Digit::Pos,
443 Digit::Zero => other.not_negative(),
444 Digit::Pos => other,
445 }
446 }
447
448 /// Performs RM3 implication with the current `Digit` as `self` and another `Digit`.
449 ///
450 /// - `self`: The antecedent of the implication.
451 /// - `other`: The consequent of the implication.
452 ///
453 /// - Returns:
454 /// - `Digit::Pos` when `self` is `Digit::Neg`.
455 /// - `other` when `self` is `Digit::Zero`.
456 /// - The necessary condition of `other` when `self` is `Digit::Pos`.
457 ///
458 /// Implements RM3 ternary implication logic, which defines a unique
459 /// perspective for implication operations in balanced ternary systems.
460 pub const fn rm3_imply(self, other: Self) -> Self {
461 match self {
462 Digit::Neg => Digit::Pos,
463 Digit::Zero => other,
464 Digit::Pos => other.necessary(),
465 }
466 }
467
468 /// Performs the paraconsistent-logic implication with the current `Digit` as `self` and another `Digit`.
469 ///
470 /// - `self`: The antecedent of the implication.
471 /// - `other`: The consequent of the implication.
472 ///
473 /// - Returns:
474 /// - `Digit::Pos` when `self` is `Digit::Neg`.
475 /// - `other` otherwise.
476 pub const fn para_imply(self, other: Self) -> Self {
477 match self {
478 Digit::Neg => Digit::Pos,
479 _ => other,
480 }
481 }
482
483 /// Performs HT implication with the current `Digit` as `self` and another `Digit`.
484 ///
485 /// - `self`: The antecedent of the implication.
486 /// - `other`: The consequent of the implication.
487 ///
488 /// - Returns:
489 /// - `Digit::Pos` when `self` is `Digit::Neg`.
490 /// - The possibility condition of `other` when `self` is `Digit::Zero`.
491 /// - `other` when `self` is `Digit::Pos`.
492 ///
493 /// This method computes HT ternary implication based on heuristic logic.
494 pub const fn ht_imply(self, other: Self) -> Self {
495 match self {
496 Digit::Neg => Digit::Pos,
497 Digit::Zero => other.possibly(),
498 Digit::Pos => other,
499 }
500 }
501
502 /// Performs HT logical negation of the current `Digit`.
503 ///
504 /// - Returns:
505 /// - `Digit::Pos` when `self` is `Digit::Neg`.
506 /// - `Digit::Neg` when `self` is `Digit::Zero` or `Digit::Pos`.
507 ///
508 /// This method evaluates the HT negation result using heuristic ternary logic.
509 pub const fn ht_not(self) -> Self {
510 match self {
511 Digit::Neg => Digit::Pos,
512 Digit::Zero => Digit::Neg,
513 Digit::Pos => Digit::Neg,
514 }
515 }
516
517 /// Converts the `Digit` to a `bool` in HT logic.
518 ///
519 /// - Returns:
520 /// - `true` when `self` is `Digit::Pos`.
521 /// - `false` when `self` is `Digit::Neg`.
522 ///
523 /// - Panics:
524 /// - Panics if `self` is `Digit::Zero`, as `Digit::Zero` cannot be directly
525 /// converted to a boolean value.
526 /// > To ensure `Pos` or `Neg` value, use one of :
527 /// > * [Digit::possibly]
528 /// > * [Digit::necessary]
529 /// > * [Digit::contingently]
530 /// > * [Digit::ht_not]
531 ///
532 pub const fn ht_bool(self) -> bool {
533 match self {
534 Digit::Neg => false,
535 Digit::Zero => panic!(
536 "Cannot convert a Digit::Zero to a bool. \
537 Use Digit::possibly()->to_bool() or Digit::necessary()->to_bool() instead."
538 ),
539 Digit::Pos => true,
540 }
541 }
542
543 /// Performs Post's negation of the current `Digit`.
544 ///
545 /// - Returns:
546 /// - `Digit::Zero` when `self` is `Digit::Neg`.
547 /// - `Digit::Pos` when `self` is `Digit::Zero`.
548 /// - `Digit::Neg` when `self` is `Digit::Pos`.
549 ///
550 /// This method evaluates the negation based on Post's logic in ternary systems,
551 /// which differs from standard negation logic.
552 pub const fn post(self) -> Self {
553 match self {
554 Digit::Neg => Digit::Zero,
555 Digit::Zero => Digit::Pos,
556 Digit::Pos => Digit::Neg,
557 }
558 }
559
560 /// Performs the inverse operation from the Post's negation of the current `Digit`.
561 ///
562 /// - Returns:
563 /// - `Digit::Pos` when `self` is `Digit::Neg`.
564 /// - `Digit::Neg` when `self` is `Digit::Zero`.
565 /// - `Digit::Zero` when `self` is `Digit::Pos`.
566 pub const fn pre(self) -> Self {
567 match self {
568 Digit::Neg => Digit::Pos,
569 Digit::Zero => Digit::Neg,
570 Digit::Pos => Digit::Zero,
571 }
572 }
573
574 /// This method maps this `Digit` value to its corresponding unbalanced ternary
575 /// integer representation.
576 ///
577 /// - Returns:
578 /// - `0` for `Digit::Neg`.
579 /// - `1` for `Digit::Zero`.
580 /// - `2` for `Digit::Pos`.
581 ///
582 pub const fn to_unbalanced(self) -> u8 {
583 match self {
584 Digit::Neg => 0,
585 Digit::Zero => 1,
586 Digit::Pos => 2,
587 }
588 }
589
590 /// Creates a `Digit` from an unbalanced ternary integer representation.
591 ///
592 /// # Arguments:
593 /// - `u`: An unsigned 8-bit integer representing an unbalanced ternary value.
594 ///
595 /// # Returns:
596 /// - `Digit::Neg` for `0`.
597 /// - `Digit::Zero` for `1`.
598 /// - `Digit::Pos` for `2`.
599 ///
600 /// # Panics:
601 /// - Panics if the provided value is not `0`, `1`, or `2`, as these are the
602 /// only valid representations of unbalanced ternary values.
603 pub const fn from_unbalanced(u: u8) -> Digit {
604 match u {
605 0 => Digit::Neg,
606 1 => Digit::Zero,
607 2 => Digit::Pos,
608 _ => panic!("Invalid value. A unbalanced ternary value must be either 0, 1 or 2."),
609 }
610 }
611
612 /// Increments the `Digit` value and returns a `Ternary` result.
613 ///
614 /// - The rules for incrementing are based on ternary arithmetic:
615 /// - For `Digit::Neg`:
616 /// - Incrementing results in `Digit::Zero` (`Ternary::parse("0")`).
617 /// - For `Digit::Zero`:
618 /// - Incrementing results in `Digit::Pos` (`Ternary::parse("+")`).
619 /// - For `Digit::Pos`:
620 /// - Incrementing results in "overflow" (`Ternary::parse("+-")`).
621 ///
622 /// - Returns:
623 /// - A `Ternary` instance representing the result of the increment operation.
624 pub fn inc(self) -> Ternary {
625 match self {
626 Digit::Neg => Ternary::parse("0"),
627 Digit::Zero => Ternary::parse("+"),
628 Digit::Pos => Ternary::parse("+-"),
629 }
630 }
631
632 /// Decrements the `Digit` value and returns a `Ternary` result.
633 ///
634 /// - The rules for decrementing are based on ternary arithmetic:
635 /// - For `Digit::Neg`:
636 /// - Decrementing results in "underflow" (`Ternary::parse("-+")`).
637 /// - For `Digit::Zero`:
638 /// - Decrementing results in `Digit::Neg` (`Ternary::parse("-")`).
639 /// - For `Digit::Pos`:
640 /// - Decrementing results in `Digit::Zero` (`Ternary::parse("0")`).
641 ///
642 /// - Returns:
643 /// - A `Ternary` instance representing the result of the decrement operation.
644 pub fn dec(self) -> Ternary {
645 match self {
646 Digit::Neg => Ternary::parse("-+"),
647 Digit::Zero => Ternary::parse("-"),
648 Digit::Pos => Ternary::parse("0"),
649 }
650 }
651}
652
653impl Neg for Digit {
654 type Output = Self;
655
656 /// Returns the negation of the `Digit`.
657 ///
658 /// - `Digit::Neg` becomes `Digit::Pos`
659 /// - `Digit::Pos` becomes `Digit::Neg`
660 /// - `Digit::Zero` remains `Digit::Zero`
661 fn neg(self) -> Self::Output {
662 match self {
663 Digit::Neg => Digit::Pos,
664 Digit::Zero => Digit::Zero,
665 Digit::Pos => Digit::Neg,
666 }
667 }
668}
669
670impl Not for Digit {
671 type Output = Self;
672 fn not(self) -> Self::Output {
673 -self
674 }
675}
676
677impl Add<Digit> for Digit {
678 type Output = Ternary;
679
680 /// Adds two `Digit` values together and returns a `Ternary` result.
681 ///
682 /// - The rules for addition are based on ternary arithmetic:
683 /// - For `Digit::Neg`:
684 /// - Adding `Digit::Neg` results in "underflow" (`Ternary::parse("-+")`).
685 /// - Adding `Digit::Zero` keeps the result as `Digit::Neg` (`Ternary::parse("-")`).
686 /// - Adding `Digit::Pos` results in a balance (`Ternary::parse("0")`).
687 /// - For `Digit::Zero`:
688 /// - Simply returns the other operand wrapped in a `Ternary` object.
689 /// - For `Digit::Pos`:
690 /// - Adding `Digit::Neg` results in balance (`Ternary::parse("0")`).
691 /// - Adding `Digit::Zero` keeps the result as `Digit::Pos` (`Ternary::parse("+")`).
692 /// - Adding `Digit::Pos` results in "overflow" (`Ternary::parse("+-")`).
693 ///
694 /// - Returns:
695 /// - A `Ternary` instance that holds the result of the addition.
696 ///
697 /// - Panics:
698 /// - This method does not panic under any circumstances.
699 fn add(self, other: Digit) -> Self::Output {
700 match self {
701 Digit::Neg => other.dec(),
702 Digit::Zero => Ternary::new(vec![other]),
703 Digit::Pos => other.inc(),
704 }
705 }
706}
707
708impl Sub<Digit> for Digit {
709 type Output = Ternary;
710
711 /// Subtracts two `Digit` values and returns a `Ternary` result.
712 ///
713 /// - The rules for subtraction are based on ternary arithmetic:
714 /// - For `Digit::Neg`:
715 /// - Subtracting `Digit::Neg` results in balance (`Ternary::parse("0")`).
716 /// - Subtracting `Digit::Zero` keeps the result as `Digit::Neg` (`Ternary::parse("-")`).
717 /// - Subtracting `Digit::Pos` results in "underflow" (`Ternary::parse("-+")`).
718 /// - For `Digit::Zero`:
719 /// - Simply negates the other operand and returns it wrapped in a `Ternary` object.
720 /// - For `Digit::Pos`:
721 /// - Subtracting `Digit::Neg` results in "overflow" (`Ternary::parse("+-")`).
722 /// - Subtracting `Digit::Zero` keeps the result as `Digit::Pos` (`Ternary::parse("+")`).
723 /// - Subtracting `Digit::Pos` results in balance (`Ternary::parse("0")`).
724 ///
725 /// - Returns:
726 /// - A `Ternary` instance that holds the result of the subtraction.
727 ///
728 /// - Panics:
729 /// - This method does not panic under any circumstances.
730 fn sub(self, other: Digit) -> Self::Output {
731 match self {
732 Digit::Neg => other.inc(),
733 Digit::Zero => Ternary::new(vec![-other]),
734 Digit::Pos => other.dec(),
735 }
736 }
737}
738
739impl Mul<Digit> for Digit {
740 type Output = Digit;
741
742 /// Multiplies two `Digit` values together and returns the product as a `Digit`.
743 ///
744 /// - The rules for multiplication in this implementation are straightforward:
745 /// - `Digit::Neg` multiplied by:
746 /// - `Digit::Neg` results in `Digit::Pos`.
747 /// - `Digit::Zero` results in `Digit::Zero`.
748 /// - `Digit::Pos` results in `Digit::Neg`.
749 /// - `Digit::Zero` multiplied by any `Digit` always results in `Digit::Zero`.
750 /// - `Digit::Pos` multiplied by:
751 /// - `Digit::Neg` results in `Digit::Neg`.
752 /// - `Digit::Zero` results in `Digit::Zero`.
753 /// - `Digit::Pos` results in `Digit::Pos`.
754 ///
755 /// - Returns:
756 /// - A `Digit` instance representing the result of the multiplication.
757 fn mul(self, other: Digit) -> Self::Output {
758 match self {
759 Digit::Neg => -other,
760 Digit::Zero => Digit::Zero,
761 Digit::Pos => other,
762 }
763 }
764}
765
766impl Div<Digit> for Digit {
767 type Output = Digit;
768
769 /// Divides one `Digit` value by another and returns the result as a `Digit`.
770 ///
771 /// # Rules for division:
772 /// - For `Digit::Neg`:
773 /// - Dividing `Digit::Neg` by `Digit::Neg` results in `Digit::Pos`.
774 /// - Dividing `Digit::Neg` by `Digit::Zero` will panic with "Cannot divide by zero."
775 /// - Dividing `Digit::Neg` by `Digit::Pos` results in `Digit::Neg`.
776 /// - For `Digit::Zero`:
777 /// - Dividing `Digit::Zero` by `Digit::Neg` results in `Digit::Zero`.
778 /// - Dividing `Digit::Zero` by `Digit::Zero` will panic with "Cannot divide by zero."
779 /// - Dividing `Digit::Zero` by `Digit::Pos` results in `Digit::Zero`.
780 /// - For `Digit::Pos`:
781 /// - Dividing `Digit::Pos` by `Digit::Neg` results in `Digit::Neg`.
782 /// - Dividing `Digit::Pos` by `Digit::Zero` will panic with "Cannot divide by zero."
783 /// - Dividing `Digit::Pos` by `Digit::Pos` results in `Digit::Pos`.
784 ///
785 /// # Returns:
786 /// - A `Digit` value representing the result of the division.
787 ///
788 /// # Panics:
789 /// - Panics with "Cannot divide by zero." if the `other` operand is `Digit::Zero`.
790 fn div(self, other: Digit) -> Self::Output {
791 if other == Digit::Zero {
792 panic!("Cannot divide by zero.");
793 }
794 self * other
795 }
796}
797
798impl BitAnd for Digit {
799 type Output = Self;
800
801 /// Performs a bitwise AND operation between two `Digit` values and returns the result.
802 ///
803 /// - The rules for the bitwise AND (`&`) operation are:
804 /// - If `self` is `Digit::Neg`, the result is always `Digit::Neg`.
805 /// - If `self` is `Digit::Zero`, the result depends on the value of `other`:
806 /// - `Digit::Neg` results in `Digit::Neg`.
807 /// - Otherwise, the result is `Digit::Zero`.
808 /// - If `self` is `Digit::Pos`, the result is simply `other`.
809 ///
810 /// # Returns:
811 /// - A `Digit` value that is the result of the bitwise AND operation.
812 ///
813 /// # Examples:
814 /// ```
815 /// use balanced_ternary::Digit;
816 /// use Digit::{Neg, Pos, Zero};
817 ///
818 /// assert_eq!(Neg & Pos, Neg);
819 /// assert_eq!(Zero & Neg, Neg);
820 /// assert_eq!(Zero & Pos, Zero);
821 /// assert_eq!(Pos & Zero, Zero);
822 /// ```
823 fn bitand(self, other: Self) -> Self::Output {
824 match self {
825 Digit::Neg => Digit::Neg,
826 Digit::Zero => other.negative(),
827 Digit::Pos => other,
828 }
829 }
830}
831
832impl BitOr for Digit {
833 type Output = Self;
834
835 /// Performs a bitwise OR operation between two `Digit` values and returns the result.
836 ///
837 /// - The rules for the bitwise OR (`|`) operation are as follows:
838 /// - If `self` is `Digit::Neg`, the result is always the value of `other`.
839 /// - If `self` is `Digit::Zero`, the result depends on the value of `other`:
840 /// - `Digit::Pos` results in `Digit::Pos`.
841 /// - Otherwise, the result is `Digit::Zero`.
842 /// - If `self` is `Digit::Pos`, the result is always `Digit::Pos`.
843 ///
844 /// # Returns:
845 /// - A `Digit` value that is the result of the bitwise OR operation.
846 ///
847 /// # Examples:
848 /// ```
849 /// use balanced_ternary::Digit;
850 /// use Digit::{Neg, Pos, Zero};
851 ///
852 /// assert_eq!(Neg | Pos, Pos);
853 /// assert_eq!(Zero | Neg, Zero);
854 /// assert_eq!(Zero | Pos, Pos);
855 /// assert_eq!(Pos | Zero, Pos);
856 /// ```
857 fn bitor(self, other: Self) -> Self::Output {
858 match self {
859 Digit::Neg => other,
860 Digit::Zero => other.positive(),
861 Digit::Pos => Digit::Pos,
862 }
863 }
864}
865
866impl BitXor for Digit {
867 type Output = Self;
868
869 /// Performs a bitwise XOR (exclusive OR) operation between two `Digit` values.
870 ///
871 /// - The rules for the bitwise XOR (`^`) operation are as follows:
872 /// - If `self` is `Digit::Neg`, the result is always the value of `rhs`.
873 /// - If `self` is `Digit::Zero`, the result is always `Digit::Zero`.
874 /// - If `self` is `Digit::Pos`, the result is the negation of `rhs`:
875 /// - `Digit::Neg` becomes `Digit::Pos`.
876 /// - `Digit::Zero` becomes `Digit::Zero`.
877 /// - `Digit::Pos` becomes `Digit::Neg`.
878 ///
879 /// # Returns:
880 /// - A `Digit` value that is the result of the bitwise XOR operation.
881 ///
882 /// # Examples:
883 /// ```
884 /// use balanced_ternary::Digit;
885 /// use Digit::{Neg, Pos, Zero};
886 ///
887 /// assert_eq!(Neg ^ Pos, Pos);
888 /// assert_eq!(Zero ^ Neg, Zero);
889 /// assert_eq!(Pos ^ Pos, Neg);
890 /// ```
891 fn bitxor(self, rhs: Self) -> Self::Output {
892 match self {
893 Digit::Neg => rhs,
894 Digit::Zero => Digit::Zero,
895 Digit::Pos => -rhs,
896 }
897 }
898}