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
118 /// Converts the `Digit` into a character representation.
119 ///
120 /// - Returns:
121 /// - `Θ` for `Digit::Neg`
122 /// - `0` for `Digit::Zero`
123 /// - `1` for `Digit::Pos`
124 pub const fn to_char_theta(&self) -> char {
125 match self {
126 Digit::Neg => 'Θ',
127 Digit::Zero => '0',
128 Digit::Pos => '1',
129 }
130 }
131
132
133 /// Converts the `Digit` into a character representation.
134 ///
135 /// - Returns:
136 /// - `Z` for `Digit::Neg`
137 /// - `0` for `Digit::Zero`
138 /// - `1` for `Digit::Pos`
139 pub const fn to_char_z(&self) -> char {
140 match self {
141 Digit::Neg => 'Z',
142 Digit::Zero => '0',
143 Digit::Pos => '1',
144 }
145 }
146
147 /// Converts the `Digit` into a character representation.
148 ///
149 /// - Returns:
150 /// - `T` for `Digit::Neg`
151 /// - `0` for `Digit::Zero`
152 /// - `1` for `Digit::Pos`
153 pub const fn to_char_t(&self) -> char {
154 match self {
155 Digit::Neg => 'T',
156 Digit::Zero => '0',
157 Digit::Pos => '1',
158 }
159 }
160
161 /// Creates a `Digit` from a character representation.
162 ///
163 /// - Accepts:
164 /// - `Θ` for `Digit::Neg`
165 /// - `0` for `Digit::Zero`
166 /// - `1` for `Digit::Pos`
167 /// - Panics if the input character is invalid.
168 pub const fn from_char_theta(c: char) -> Digit {
169 match c {
170 'Θ' => Digit::Neg,
171 '0' => Digit::Zero,
172 '1' => Digit::Pos,
173 _ => panic!("Invalid value. Expected 'Θ', '0', or '1'."),
174 }
175 }
176
177 /// Creates a `Digit` from a character representation.
178 ///
179 /// - Accepts:
180 /// - `Z` for `Digit::Neg`
181 /// - `0` for `Digit::Zero`
182 /// - `1` for `Digit::Pos`
183 /// - Panics if the input character is invalid.
184 pub const fn from_char_z(c: char) -> Digit {
185 match c {
186 'Z' => Digit::Neg,
187 '0' => Digit::Zero,
188 '1' => Digit::Pos,
189 _ => panic!("Invalid value. Expected 'Z', '0', or '1'."),
190 }
191 }
192
193 /// Creates a `Digit` from a character representation.
194 ///
195 /// - Accepts:
196 /// - `T` for `Digit::Neg`
197 /// - `0` for `Digit::Zero`
198 /// - `1` for `Digit::Pos`
199 /// - Panics if the input character is invalid.
200 pub const fn from_char_t(c: char) -> Digit {
201 match c {
202 'T' => Digit::Neg,
203 '0' => Digit::Zero,
204 '1' => Digit::Pos,
205 _ => panic!("Invalid value. Expected 'T', '0', or '1'."),
206 }
207 }
208
209 /// Converts the `Digit` into its character representation.
210 ///
211 /// - Returns:
212 /// - `-` for `Digit::Neg`
213 /// - `0` for `Digit::Zero`
214 /// - `+` for `Digit::Pos`
215 pub const fn to_char(&self) -> char {
216 match self {
217 Digit::Neg => '-',
218 Digit::Zero => '0',
219 Digit::Pos => '+',
220 }
221 }
222
223 /// Creates a `Digit` from its character representation.
224 ///
225 /// - Accepts:
226 /// - `-` for `Digit::Neg`
227 /// - `0` for `Digit::Zero`
228 /// - `+` for `Digit::Pos`
229 /// - Panics if the input character is invalid.
230 pub const fn from_char(c: char) -> Digit {
231 match c {
232 '-' => Digit::Neg,
233 '0' => Digit::Zero,
234 '+' => Digit::Pos,
235 _ => panic!("Invalid value. A Ternary must be either -, 0 or +."),
236 }
237 }
238
239 /// Converts the `Digit` into its integer representation.
240 ///
241 /// - Returns:
242 /// - -1 for `Digit::Neg`
243 /// - 0 for `Digit::Zero`
244 /// - 1 for `Digit::Pos`
245 pub const fn to_i8(&self) -> i8 {
246 match self {
247 Digit::Neg => -1,
248 Digit::Zero => 0,
249 Digit::Pos => 1,
250 }
251 }
252
253 /// Creates a `Digit` from its integer representation.
254 ///
255 /// - Accepts:
256 /// - -1 for `Digit::Neg`
257 /// - 0 for `Digit::Zero`
258 /// - 1 for `Digit::Pos`
259 /// - Panics if the input integer is invalid.
260 pub const fn from_i8(i: i8) -> Digit {
261 match i {
262 -1 => Digit::Neg,
263 0 => Digit::Zero,
264 1 => Digit::Pos,
265 _ => panic!("Invalid value. A Ternary must be either -1, 0 or +1."),
266 }
267 }
268
269 /// Returns the corresponding possible value of the current `Digit`.
270 ///
271 /// - Returns:
272 /// - `Digit::Neg` for `Digit::Neg`
273 /// - `Digit::Pos` for `Digit::Zero`
274 /// - `Digit::Pos` for `Digit::Pos`
275 pub const fn possibly(self) -> Self {
276 match self {
277 Digit::Neg => Digit::Neg,
278 Digit::Zero => Digit::Pos,
279 Digit::Pos => Digit::Pos,
280 }
281 }
282
283 /// Determines the condition of necessity for the current `Digit`.
284 ///
285 /// - Returns:
286 /// - `Digit::Neg` for `Digit::Neg`
287 /// - `Digit::Neg` for `Digit::Zero`
288 /// - `Digit::Pos` for `Digit::Pos`
289 ///
290 /// This method is used to calculate necessity as part
291 /// of balanced ternary logic systems.
292 pub const fn necessary(self) -> Self {
293 match self {
294 Digit::Neg => Digit::Neg,
295 Digit::Zero => Digit::Neg,
296 Digit::Pos => Digit::Pos,
297 }
298 }
299
300 /// Determines the condition of contingency for the current `Digit`.
301 ///
302 /// - Returns:
303 /// - `Digit::Neg` for `Digit::Neg`
304 /// - `Digit::Pos` for `Digit::Zero`
305 /// - `Digit::Neg` for `Digit::Pos`
306 ///
307 /// This method represents contingency in balanced ternary logic,
308 /// which defines the specific alternation of `Digit` values.
309 pub const fn contingently(self) -> Self {
310 match self {
311 Digit::Neg => Digit::Neg,
312 Digit::Zero => Digit::Pos,
313 Digit::Pos => Digit::Neg,
314 }
315 }
316
317 /// Returns the absolute positive value of the current `Digit`.
318 ///
319 /// - Returns:
320 /// - `Digit::Pos` for `Digit::Neg`
321 /// - `Digit::Zero` for `Digit::Zero`
322 /// - `Digit::Pos` for `Digit::Pos`
323 pub const fn absolute_positive(self) -> Self {
324 match self {
325 Digit::Neg => Digit::Pos,
326 Digit::Zero => Digit::Zero,
327 Digit::Pos => Digit::Pos,
328 }
329 }
330
331 /// Determines the strictly positive condition for the current `Digit`.
332 ///
333 /// - Returns:
334 /// - `Digit::Zero` for `Digit::Neg`
335 /// - `Digit::Zero` for `Digit::Zero`
336 /// - `Digit::Pos` for `Digit::Pos`
337 ///
338 /// This method is used to calculate strictly positive states
339 /// in association with ternary logic.
340 pub const fn positive(self) -> Self {
341 match self {
342 Digit::Neg => Digit::Zero,
343 Digit::Zero => Digit::Zero,
344 Digit::Pos => Digit::Pos,
345 }
346 }
347
348 /// Determines the condition of non-negativity for the current `Digit`.
349 ///
350 /// - Returns:
351 /// - `Digit::Zero` for `Digit::Neg`
352 /// - `Digit::Pos` for `Digit::Zero`
353 /// - `Digit::Pos` for `Digit::Pos`
354 ///
355 /// This method is used to filter out negative conditions
356 /// in computations with balanced ternary representations.
357 pub const fn not_negative(self) -> Self {
358 match self {
359 Digit::Neg => Digit::Zero,
360 Digit::Zero => Digit::Pos,
361 Digit::Pos => Digit::Pos,
362 }
363 }
364
365 /// Determines the condition of non-positivity for the current `Digit`.
366 ///
367 /// - Returns:
368 /// - `Digit::Neg` for `Digit::Neg`
369 /// - `Digit::Neg` for `Digit::Zero`
370 /// - `Digit::Zero` for `Digit::Pos`
371 ///
372 /// This method complements the `positive` condition and captures
373 /// states that are not strictly positive.
374 pub const fn not_positive(self) -> Self {
375 match self {
376 Digit::Neg => Digit::Neg,
377 Digit::Zero => Digit::Neg,
378 Digit::Pos => Digit::Zero,
379 }
380 }
381
382 /// Determines the strictly negative condition for the current `Digit`.
383 ///
384 /// - Returns:
385 /// - `Digit::Neg` for `Digit::Neg`
386 /// - `Digit::Zero` for `Digit::Zero`
387 /// - `Digit::Zero` for `Digit::Pos`
388 ///
389 /// This method calculates strictly negative states
390 /// in association with ternary logic.
391 pub const fn negative(self) -> Self {
392 match self {
393 Digit::Neg => Digit::Neg,
394 Digit::Zero => Digit::Zero,
395 Digit::Pos => Digit::Zero,
396 }
397 }
398
399 /// Returns the absolute negative value of the current `Digit`.
400 ///
401 /// - Returns:
402 /// - `Digit::Neg` for `Digit::Neg`
403 /// - `Digit::Zero` for `Digit::Zero`
404 /// - `Digit::Neg` for `Digit::Pos`
405 pub const fn absolute_negative(self) -> Self {
406 match self {
407 Digit::Neg => Digit::Neg,
408 Digit::Zero => Digit::Zero,
409 Digit::Pos => Digit::Neg,
410 }
411 }
412
413 /// Performs Kleene implication with the current `Digit` as `self` and another `Digit`.
414 ///
415 /// - `self`: The antecedent of the implication.
416 /// - `other`: The consequent of the implication.
417 ///
418 /// - Returns:
419 /// - `Digit::Pos` when `self` is `Digit::Neg`.
420 /// - The positive condition of `other` when `self` is `Digit::Zero`.
421 /// - `other` when `self` is `Digit::Pos`.
422 ///
423 /// Implements Kleene ternary implication logic, which includes
424 /// determining the logical result based on antecedent and consequent.
425 pub const fn k3_imply(self, other: Self) -> Self {
426 match self {
427 Digit::Neg => Digit::Pos,
428 Digit::Zero => other.positive(),
429 Digit::Pos => other,
430 }
431 }
432
433 /// Apply a ternary equivalence operation for the current `Digit` and another `Digit`.
434 ///
435 /// - `self`: The first operand of the equivalence operation.
436 /// - `other`: The second operand of the equivalence operation.
437 ///
438 /// - Returns:
439 /// - The negation of `other` when `self` is `Digit::Neg`.
440 /// - `Digit::Zero` when `self` is `Digit::Zero`.
441 /// - `other` when `self` is `Digit::Pos`.
442 ///
443 /// This method implements a ternary logic equivalence, which captures the relationship between
444 /// two balanced ternary `Digit`s based on their logical equivalence.
445 pub const fn k3_equiv(self, other: Self) -> Self {
446 match self {
447 Digit::Neg => match other {
448 Digit::Neg => Digit::Pos,
449 Digit::Zero => Digit::Zero,
450 Digit::Pos => Digit::Neg,
451 },
452 Digit::Zero => Digit::Zero,
453 Digit::Pos => other,
454 }
455 }
456
457 /// Performs a ternary AND operation for the current `Digit` and another `Digit`.
458 ///
459 /// - `self`: The first operand of the AND operation.
460 /// - `other`: The second operand of the AND operation.
461 ///
462 /// - Returns:
463 /// - `Digit::Neg` if `self` is `Digit::Neg` and `other` is not `Digit::Zero`.
464 /// - `Digit::Zero` if either `self` or `other` is `Digit::Zero`.
465 /// - `other` if `self` is `Digit::Pos`.
466 ///
467 /// This method implements Bochvar's internal three-valued logic in balanced ternary AND operation,
468 /// which evaluates the logical conjunction of two `Digit`s in the ternary logic system.
469 pub const fn bi3_and(self, other: Self) -> Self {
470 match self {
471 Digit::Neg => other.absolute_negative(),
472 Digit::Zero => Digit::Zero,
473 Digit::Pos => other,
474 }
475 }
476
477 /// Performs a ternary OR operation for the current `Digit` and another `Digit`.
478 ///
479 /// - `self`: The first operand of the OR operation.
480 /// - `other`: The second operand of the OR operation.
481 ///
482 /// - Returns:
483 /// - `other` if `self` is `Digit::Neg`.
484 /// - `Digit::Zero` if `self` is `Digit::Zero`.
485 /// - `Digit::Pos` if `self` is `Digit::Pos` and `other` is not `Digit::Zero`.
486 ///
487 /// This method implements Bochvar's three-valued internal ternary logic for the OR operation,
488 /// determining the logical disjunction of two balanced ternary `Digit`s.
489 pub const fn bi3_or(self, other: Self) -> Self {
490 match self {
491 Digit::Neg => other,
492 Digit::Zero => Digit::Zero,
493 Digit::Pos => other.absolute_positive(),
494 }
495 }
496
497 /// Performs Bochvar's internal three-valued implication with the current `Digit` as `self`
498 /// and another `Digit` as the consequent.
499 ///
500 /// - `self`: The antecedent of the implication.
501 /// - `other`: The consequent of the implication.
502 ///
503 /// - Returns:
504 /// - `Digit::Zero` if `self` is `Digit::Neg` and `other` is `Digit::Zero`.
505 /// - `Digit::Pos` if `self` is `Digit::Neg` and `other` is not `Digit::Zero`.
506 /// - `Digit::Zero` if `self` is `Digit::Zero`.
507 /// - `other` if `self` is `Digit::Pos`.
508 ///
509 /// This method implements Bochvar's internal implication logic, which evaluates
510 /// the logical consequence, between two balanced ternary `Digit`s in a manner
511 /// consistent with three-valued logic principles.
512 pub const fn bi3_imply(self, other: Self) -> Self {
513 match self {
514 Digit::Neg => other.absolute_positive(),
515 Digit::Zero => Digit::Zero,
516 Digit::Pos => other,
517 }
518 }
519
520 /// Performs Łukasiewicz implication with the current `Digit` as `self` and another `Digit`.
521 ///
522 /// - `self`: The antecedent of the implication.
523 /// - `other`: The consequent of the implication.
524 ///
525 /// - Returns:
526 /// - `Digit::Pos` when `self` is `Digit::Neg`.
527 /// - The non-negative condition of `other` when `self` is `Digit::Zero`.
528 /// - `other` when `self` is `Digit::Pos`.
529 ///
530 /// Implements Łukasiewicz ternary implication logic, which
531 /// evaluates an alternative approach for implication compared to Kleene logic.
532 pub const fn l3_imply(self, other: Self) -> Self {
533 match self {
534 Digit::Neg => Digit::Pos,
535 Digit::Zero => other.not_negative(),
536 Digit::Pos => other,
537 }
538 }
539
540 /// Performs RM3 implication with the current `Digit` as `self` and another `Digit`.
541 ///
542 /// - `self`: The antecedent of the implication.
543 /// - `other`: The consequent of the implication.
544 ///
545 /// - Returns:
546 /// - `Digit::Pos` when `self` is `Digit::Neg`.
547 /// - `other` when `self` is `Digit::Zero`.
548 /// - The necessary condition of `other` when `self` is `Digit::Pos`.
549 ///
550 /// Implements RM3 ternary implication logic, which defines a unique
551 /// perspective for implication operations in balanced ternary systems.
552 pub const fn rm3_imply(self, other: Self) -> Self {
553 match self {
554 Digit::Neg => Digit::Pos,
555 Digit::Zero => other,
556 Digit::Pos => other.necessary(),
557 }
558 }
559
560 /// Performs the paraconsistent-logic implication with the current `Digit` as `self` and another `Digit`.
561 ///
562 /// - `self`: The antecedent of the implication.
563 /// - `other`: The consequent of the implication.
564 ///
565 /// - Returns:
566 /// - `Digit::Pos` when `self` is `Digit::Neg`.
567 /// - `other` otherwise.
568 pub const fn para_imply(self, other: Self) -> Self {
569 match self {
570 Digit::Neg => Digit::Pos,
571 _ => other,
572 }
573 }
574
575 /// Performs HT implication with the current `Digit` as `self` and another `Digit`.
576 ///
577 /// - `self`: The antecedent of the implication.
578 /// - `other`: The consequent of the implication.
579 ///
580 /// - Returns:
581 /// - `Digit::Pos` when `self` is `Digit::Neg`.
582 /// - The possibility condition of `other` when `self` is `Digit::Zero`.
583 /// - `other` when `self` is `Digit::Pos`.
584 ///
585 /// This method computes HT ternary implication based on heuristic logic.
586 pub const fn ht_imply(self, other: Self) -> Self {
587 match self {
588 Digit::Neg => Digit::Pos,
589 Digit::Zero => other.possibly(),
590 Digit::Pos => other,
591 }
592 }
593
594 /// Performs HT logical negation of the current `Digit`.
595 ///
596 /// - Returns:
597 /// - `Digit::Pos` when `self` is `Digit::Neg`.
598 /// - `Digit::Neg` when `self` is `Digit::Zero` or `Digit::Pos`.
599 ///
600 /// This method evaluates the HT negation result using heuristic ternary logic.
601 pub const fn ht_not(self) -> Self {
602 match self {
603 Digit::Neg => Digit::Pos,
604 Digit::Zero => Digit::Neg,
605 Digit::Pos => Digit::Neg,
606 }
607 }
608
609 /// Converts the `Digit` to a `bool` in HT logic.
610 ///
611 /// - Returns:
612 /// - `true` when `self` is `Digit::Pos`.
613 /// - `false` when `self` is `Digit::Neg`.
614 ///
615 /// - Panics:
616 /// - Panics if `self` is `Digit::Zero`, as `Digit::Zero` cannot be directly
617 /// converted to a boolean value.
618 /// > To ensure `Pos` or `Neg` value, use one of :
619 /// > * [Digit::possibly]
620 /// > * [Digit::necessary]
621 /// > * [Digit::contingently]
622 /// > * [Digit::ht_not]
623 ///
624 pub const fn ht_bool(self) -> bool {
625 match self {
626 Digit::Neg => false,
627 Digit::Zero => panic!(
628 "Cannot convert a Digit::Zero to a bool. \
629 Use Digit::possibly()->to_bool() or Digit::necessary()->to_bool() instead."
630 ),
631 Digit::Pos => true,
632 }
633 }
634
635 /// Performs Post's negation of the current `Digit`.
636 ///
637 /// - Returns:
638 /// - `Digit::Zero` when `self` is `Digit::Neg`.
639 /// - `Digit::Pos` when `self` is `Digit::Zero`.
640 /// - `Digit::Neg` when `self` is `Digit::Pos`.
641 ///
642 /// This method evaluates the negation based on Post's logic in ternary systems,
643 /// which differs from standard negation logic.
644 pub const fn post(self) -> Self {
645 match self {
646 Digit::Neg => Digit::Zero,
647 Digit::Zero => Digit::Pos,
648 Digit::Pos => Digit::Neg,
649 }
650 }
651
652 /// Performs the inverse operation from the Post's negation of the current `Digit`.
653 ///
654 /// - Returns:
655 /// - `Digit::Pos` when `self` is `Digit::Neg`.
656 /// - `Digit::Neg` when `self` is `Digit::Zero`.
657 /// - `Digit::Zero` when `self` is `Digit::Pos`.
658 pub const fn pre(self) -> Self {
659 match self {
660 Digit::Neg => Digit::Pos,
661 Digit::Zero => Digit::Neg,
662 Digit::Pos => Digit::Zero,
663 }
664 }
665
666 /// This method maps this `Digit` value to its corresponding unbalanced ternary
667 /// integer representation.
668 ///
669 /// - Returns:
670 /// - `0` for `Digit::Neg`.
671 /// - `1` for `Digit::Zero`.
672 /// - `2` for `Digit::Pos`.
673 ///
674 pub const fn to_unbalanced(self) -> u8 {
675 match self {
676 Digit::Neg => 0,
677 Digit::Zero => 1,
678 Digit::Pos => 2,
679 }
680 }
681
682 /// Creates a `Digit` from an unbalanced ternary integer representation.
683 ///
684 /// # Arguments:
685 /// - `u`: An unsigned 8-bit integer representing an unbalanced ternary value.
686 ///
687 /// # Returns:
688 /// - `Digit::Neg` for `0`.
689 /// - `Digit::Zero` for `1`.
690 /// - `Digit::Pos` for `2`.
691 ///
692 /// # Panics:
693 /// - Panics if the provided value is not `0`, `1`, or `2`, as these are the
694 /// only valid representations of unbalanced ternary values.
695 pub const fn from_unbalanced(u: u8) -> Digit {
696 match u {
697 0 => Digit::Neg,
698 1 => Digit::Zero,
699 2 => Digit::Pos,
700 _ => panic!("Invalid value. A unbalanced ternary value must be either 0, 1 or 2."),
701 }
702 }
703
704 /// Increments the `Digit` value and returns a `Ternary` result.
705 ///
706 /// - The rules for incrementing are based on ternary arithmetic:
707 /// - For `Digit::Neg`:
708 /// - Incrementing results in `Digit::Zero` (`Ternary::parse("0")`).
709 /// - For `Digit::Zero`:
710 /// - Incrementing results in `Digit::Pos` (`Ternary::parse("+")`).
711 /// - For `Digit::Pos`:
712 /// - Incrementing results in "overflow" (`Ternary::parse("+-")`).
713 ///
714 /// - Returns:
715 /// - A `Ternary` instance representing the result of the increment operation.
716 pub fn inc(self) -> Ternary {
717 match self {
718 Digit::Neg => Ternary::parse("0"),
719 Digit::Zero => Ternary::parse("+"),
720 Digit::Pos => Ternary::parse("+-"),
721 }
722 }
723
724 /// Decrements the `Digit` value and returns a `Ternary` result.
725 ///
726 /// - The rules for decrementing are based on ternary arithmetic:
727 /// - For `Digit::Neg`:
728 /// - Decrementing results in "underflow" (`Ternary::parse("-+")`).
729 /// - For `Digit::Zero`:
730 /// - Decrementing results in `Digit::Neg` (`Ternary::parse("-")`).
731 /// - For `Digit::Pos`:
732 /// - Decrementing results in `Digit::Zero` (`Ternary::parse("0")`).
733 ///
734 /// - Returns:
735 /// - A `Ternary` instance representing the result of the decrement operation.
736 pub fn dec(self) -> Ternary {
737 match self {
738 Digit::Neg => Ternary::parse("-+"),
739 Digit::Zero => Ternary::parse("-"),
740 Digit::Pos => Ternary::parse("0"),
741 }
742 }
743}
744
745impl Neg for Digit {
746 type Output = Self;
747
748 /// Returns the negation of the `Digit`.
749 ///
750 /// - `Digit::Neg` becomes `Digit::Pos`
751 /// - `Digit::Pos` becomes `Digit::Neg`
752 /// - `Digit::Zero` remains `Digit::Zero`
753 fn neg(self) -> Self::Output {
754 match self {
755 Digit::Neg => Digit::Pos,
756 Digit::Zero => Digit::Zero,
757 Digit::Pos => Digit::Neg,
758 }
759 }
760}
761
762impl Not for Digit {
763 type Output = Self;
764 fn not(self) -> Self::Output {
765 -self
766 }
767}
768
769impl Add<Digit> for Digit {
770 type Output = Ternary;
771
772 /// Adds two `Digit` values together and returns a `Ternary` result.
773 ///
774 /// - The rules for addition are based on ternary arithmetic:
775 /// - For `Digit::Neg`:
776 /// - Adding `Digit::Neg` results in "underflow" (`Ternary::parse("-+")`).
777 /// - Adding `Digit::Zero` keeps the result as `Digit::Neg` (`Ternary::parse("-")`).
778 /// - Adding `Digit::Pos` results in a balance (`Ternary::parse("0")`).
779 /// - For `Digit::Zero`:
780 /// - Simply returns the other operand wrapped in a `Ternary` object.
781 /// - For `Digit::Pos`:
782 /// - Adding `Digit::Neg` results in balance (`Ternary::parse("0")`).
783 /// - Adding `Digit::Zero` keeps the result as `Digit::Pos` (`Ternary::parse("+")`).
784 /// - Adding `Digit::Pos` results in "overflow" (`Ternary::parse("+-")`).
785 ///
786 /// - Returns:
787 /// - A `Ternary` instance that holds the result of the addition.
788 ///
789 /// - Panics:
790 /// - This method does not panic under any circumstances.
791 fn add(self, other: Digit) -> Self::Output {
792 match self {
793 Digit::Neg => other.dec(),
794 Digit::Zero => Ternary::new(vec![other]),
795 Digit::Pos => other.inc(),
796 }
797 }
798}
799
800impl Sub<Digit> for Digit {
801 type Output = Ternary;
802
803 /// Subtracts two `Digit` values and returns a `Ternary` result.
804 ///
805 /// - The rules for subtraction are based on ternary arithmetic:
806 /// - For `Digit::Neg`:
807 /// - Subtracting `Digit::Neg` results in balance (`Ternary::parse("0")`).
808 /// - Subtracting `Digit::Zero` keeps the result as `Digit::Neg` (`Ternary::parse("-")`).
809 /// - Subtracting `Digit::Pos` results in "underflow" (`Ternary::parse("-+")`).
810 /// - For `Digit::Zero`:
811 /// - Simply negates the other operand and returns it wrapped in a `Ternary` object.
812 /// - For `Digit::Pos`:
813 /// - Subtracting `Digit::Neg` results in "overflow" (`Ternary::parse("+-")`).
814 /// - Subtracting `Digit::Zero` keeps the result as `Digit::Pos` (`Ternary::parse("+")`).
815 /// - Subtracting `Digit::Pos` results in balance (`Ternary::parse("0")`).
816 ///
817 /// - Returns:
818 /// - A `Ternary` instance that holds the result of the subtraction.
819 ///
820 /// - Panics:
821 /// - This method does not panic under any circumstances.
822 fn sub(self, other: Digit) -> Self::Output {
823 match self {
824 Digit::Neg => other.inc(),
825 Digit::Zero => Ternary::new(vec![-other]),
826 Digit::Pos => other.dec(),
827 }
828 }
829}
830
831impl Mul<Digit> for Digit {
832 type Output = Digit;
833
834 /// Multiplies two `Digit` values together and returns the product as a `Digit`.
835 ///
836 /// - The rules for multiplication in this implementation are straightforward:
837 /// - `Digit::Neg` multiplied by:
838 /// - `Digit::Neg` results in `Digit::Pos`.
839 /// - `Digit::Zero` results in `Digit::Zero`.
840 /// - `Digit::Pos` results in `Digit::Neg`.
841 /// - `Digit::Zero` multiplied by any `Digit` always results in `Digit::Zero`.
842 /// - `Digit::Pos` multiplied by:
843 /// - `Digit::Neg` results in `Digit::Neg`.
844 /// - `Digit::Zero` results in `Digit::Zero`.
845 /// - `Digit::Pos` results in `Digit::Pos`.
846 ///
847 /// - Returns:
848 /// - A `Digit` instance representing the result of the multiplication.
849 fn mul(self, other: Digit) -> Self::Output {
850 match self {
851 Digit::Neg => -other,
852 Digit::Zero => Digit::Zero,
853 Digit::Pos => other,
854 }
855 }
856}
857
858impl Div<Digit> for Digit {
859 type Output = Digit;
860
861 /// Divides one `Digit` value by another and returns the result as a `Digit`.
862 ///
863 /// # Rules for division:
864 /// - For `Digit::Neg`:
865 /// - Dividing `Digit::Neg` by `Digit::Neg` results in `Digit::Pos`.
866 /// - Dividing `Digit::Neg` by `Digit::Zero` will panic with "Cannot divide by zero."
867 /// - Dividing `Digit::Neg` by `Digit::Pos` results in `Digit::Neg`.
868 /// - For `Digit::Zero`:
869 /// - Dividing `Digit::Zero` by `Digit::Neg` results in `Digit::Zero`.
870 /// - Dividing `Digit::Zero` by `Digit::Zero` will panic with "Cannot divide by zero."
871 /// - Dividing `Digit::Zero` by `Digit::Pos` results in `Digit::Zero`.
872 /// - For `Digit::Pos`:
873 /// - Dividing `Digit::Pos` by `Digit::Neg` results in `Digit::Neg`.
874 /// - Dividing `Digit::Pos` by `Digit::Zero` will panic with "Cannot divide by zero."
875 /// - Dividing `Digit::Pos` by `Digit::Pos` results in `Digit::Pos`.
876 ///
877 /// # Returns:
878 /// - A `Digit` value representing the result of the division.
879 ///
880 /// # Panics:
881 /// - Panics with "Cannot divide by zero." if the `other` operand is `Digit::Zero`.
882 fn div(self, other: Digit) -> Self::Output {
883 if other == Digit::Zero {
884 panic!("Cannot divide by zero.");
885 }
886 self * other
887 }
888}
889
890impl BitAnd for Digit {
891 type Output = Self;
892
893 /// Performs a bitwise AND operation between two `Digit` values and returns the result.
894 ///
895 /// - The rules for the bitwise AND (`&`) operation are:
896 /// - If `self` is `Digit::Neg`, the result is always `Digit::Neg`.
897 /// - If `self` is `Digit::Zero`, the result depends on the value of `other`:
898 /// - `Digit::Neg` results in `Digit::Neg`.
899 /// - Otherwise, the result is `Digit::Zero`.
900 /// - If `self` is `Digit::Pos`, the result is simply `other`.
901 ///
902 /// # Returns:
903 /// - A `Digit` value that is the result of the bitwise AND operation.
904 ///
905 /// # Examples:
906 /// ```
907 /// use balanced_ternary::Digit;
908 /// use Digit::{Neg, Pos, Zero};
909 ///
910 /// assert_eq!(Neg & Pos, Neg);
911 /// assert_eq!(Zero & Neg, Neg);
912 /// assert_eq!(Zero & Pos, Zero);
913 /// assert_eq!(Pos & Zero, Zero);
914 /// ```
915 fn bitand(self, other: Self) -> Self::Output {
916 match self {
917 Digit::Neg => Digit::Neg,
918 Digit::Zero => other.negative(),
919 Digit::Pos => other,
920 }
921 }
922}
923
924impl BitOr for Digit {
925 type Output = Self;
926
927 /// Performs a bitwise OR operation between two `Digit` values and returns the result.
928 ///
929 /// - The rules for the bitwise OR (`|`) operation are as follows:
930 /// - If `self` is `Digit::Neg`, the result is always the value of `other`.
931 /// - If `self` is `Digit::Zero`, the result depends on the value of `other`:
932 /// - `Digit::Pos` results in `Digit::Pos`.
933 /// - Otherwise, the result is `Digit::Zero`.
934 /// - If `self` is `Digit::Pos`, the result is always `Digit::Pos`.
935 ///
936 /// # Returns:
937 /// - A `Digit` value that is the result of the bitwise OR operation.
938 ///
939 /// # Examples:
940 /// ```
941 /// use balanced_ternary::Digit;
942 /// use Digit::{Neg, Pos, Zero};
943 ///
944 /// assert_eq!(Neg | Pos, Pos);
945 /// assert_eq!(Zero | Neg, Zero);
946 /// assert_eq!(Zero | Pos, Pos);
947 /// assert_eq!(Pos | Zero, Pos);
948 /// ```
949 fn bitor(self, other: Self) -> Self::Output {
950 match self {
951 Digit::Neg => other,
952 Digit::Zero => other.positive(),
953 Digit::Pos => Digit::Pos,
954 }
955 }
956}
957
958impl BitXor for Digit {
959 type Output = Self;
960
961 /// Performs a bitwise XOR (exclusive OR) operation between two `Digit` values.
962 ///
963 /// - The rules for the bitwise XOR (`^`) operation are as follows:
964 /// - If `self` is `Digit::Neg`, the result is always the value of `rhs`.
965 /// - If `self` is `Digit::Zero`, the result is always `Digit::Zero`.
966 /// - If `self` is `Digit::Pos`, the result is the negation of `rhs`:
967 /// - `Digit::Neg` becomes `Digit::Pos`.
968 /// - `Digit::Zero` becomes `Digit::Zero`.
969 /// - `Digit::Pos` becomes `Digit::Neg`.
970 ///
971 /// # Returns:
972 /// - A `Digit` value that is the result of the bitwise XOR operation.
973 ///
974 /// # Examples:
975 /// ```
976 /// use balanced_ternary::Digit;
977 /// use Digit::{Neg, Pos, Zero};
978 ///
979 /// assert_eq!(Neg ^ Pos, Pos);
980 /// assert_eq!(Zero ^ Neg, Zero);
981 /// assert_eq!(Pos ^ Pos, Neg);
982 /// ```
983 fn bitxor(self, rhs: Self) -> Self::Output {
984 match self {
985 Digit::Neg => rhs,
986 Digit::Zero => Digit::Zero,
987 Digit::Pos => -rhs,
988 }
989 }
990}