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