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