Package digint
digint.digint
Base-Agnostic Integer Manipulation
digint.digint
is a module focused on easy high-level integer manipulation across any numerical base. Works with binary, decimal, or any other base. digint.digint
seeks to make complex digit-level and notation operations easy, just like they were Collection
s.
Setup
This module can be installed using:
pip install digint
Usage
This module is intended to be used only as a module, and can be imported after installing using the traditional process:
from digint import digitint
Create an integer in any base
# input integers as you would with `int()`,
# if the intiger is already in the base you wish to use
n1 = digitint(1234, base=10)
n2 = digitint("BASE36", base=36)
n3 = digitint(0xABCDEF, base=16)
# convert bases on initialization, if the input is a intiger type
n4 = digitint(255, base=2) # == 0b11111111
n5 = digitint(int("BASE36", 36), base=10) # == 683248722
n6 = digitint(0xABCDEF, base=10) # == 11259375
Access and modify digits like a collection
# get the digit at index 2
print(n1.get_digit(2)) # outputs "3"
num.set_digit(2, 5)
print(n1.get_digit(2)) # outputs "5"
Easy notation
print(str(n2)) # output "BASE36"
print(str(n3)) # output "ABCDEF"
print(str(n5)) # output "683248722", as the base is set to 10
Full mutable collection implementation on integers
print(n2.pop(-1)) #outputs "6"
print(n2.pop(-1)) #outputs "3"
n2.append(int("D", 36))
print(n2) #outputs "BASED"
# The sum of all digits
print(sum(n2)) #outputs "76"
# The average of all digits
print(sum(n2)/len(n2)) #outputs "15.2"
Customizable Notation
# same as str(n3)
print(n3.notate()) # outputs "ABCDEF"
from digint import NotationFormat
fmt = NotationFormat(*tuple("0123456789ZYXWVU"))
print(n3.notate(fmt)) # outputs "ZYXWVU"
And More
There are a handfull of other ease of use features that this module provides, feel free to reference the documentation for more information.
Licence
This is licensed under the Mozilla Public License 2.0 (MPL 2.0) Licence. See the Licence file in this repository for more information.
Contribute
Contributions are always welcome! Use the github repository to report issues and contribute to this project.
Credits
While not required, feel free to credit "Markus Hammer" (or just "Markus") if you find this code or script useful for whatever you may be doing with it.
Security Policy
While the python source code will be actively maintained, any binary files (if at all provided) are in no way supported. These are provided as a courtesy and are not intended to be the main usage of this software. Please keep this in mind when choosing how you wish to use this software.
Supported Versions
Version | Supported |
---|---|
1.0.0.0 >= | ✅ |
1.0.0.0 < | ❌ |
Reporting a Vulnerability
Please report any issues to the email 107761433+MarkusHammer(THEN THE @ SYMBOL HERE)users.noreply.github.com
Mozilla Public License Version 2.0
1. Definitions
1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.
1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution" means Covered Software of a particular Contributor.
1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.
1.5. "Incompatible With Secondary Licenses" means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form" means any form of the work other than Source Code Form.
1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.
1.8. "License" means this document.
1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.
1.10. "Modifications" means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.
1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.
1.13. "Source Code Form" means the form of the work preferred for making modifications.
1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
(a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:
(a) for any code that a Contributor has removed from Covered Software; or
(b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or
(c) under Patent Claims infringed by Covered Software in the absence of its Contributions.
This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).
3.4. Notices
You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.
- *
-
- Disclaimer of Warranty *
- ------------------------- *
- *
- Covered Software is provided under this License on an "as is" *
- basis, without warranty of any kind, either expressed, implied, or *
- statutory, including, without limitation, warranties that the *
- Covered Software is free of defects, merchantable, fit for a *
- particular purpose or non-infringing. The entire risk as to the *
- quality and performance of the Covered Software is with You. *
- Should any Covered Software prove defective in any respect, You *
- (not any Contributor) assume the cost of any necessary servicing, *
- repair, or correction. This disclaimer of warranty constitutes an *
- essential part of this License. No use of any Covered Software is *
- authorized under this License except under this disclaimer. *
- *
- *
-
- Limitation of Liability *
- -------------------------- *
- *
- Under no circumstances and under no legal theory, whether tort *
- (including negligence), contract, or otherwise, shall any *
- Contributor, or anyone who distributes Covered Software as *
- permitted above, be liable to You for any direct, indirect, *
- special, incidental, or consequential damages of any character *
- including, without limitation, damages for lost profits, loss of *
- goodwill, work stoppage, computer failure or malfunction, or any *
- and all other commercial damages or losses, even if such party *
- shall have been informed of the possibility of such damages. This *
- limitation of liability shall not apply to liability for death or *
- personal injury resulting from such party's negligence to the *
- extent applicable law prohibits such limitation. Some *
- jurisdictions do not allow the exclusion or limitation of *
- incidental or consequential damages, so this exclusion and *
- limitation may not apply to You. *
- *
8. Litigation
Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
Sub-modules
digint.digint
-
digint …
digint.errors
-
errors …
digint.notation_format
-
notation_format …
digint.tests
-
init …
digint.tools
-
tools …
digint.typings
digint.userint
-
userint …
Classes
class ExtendedBasedIntiger (value: Union[int, str, Iterable[Union[int, str]]] = 0, base: int = 10, *, notation_format: Optional[NotationFormat] = NotationFormat(value_symbols=('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'), undefined_symbol='?', positive_symbol='+', negative_symbol='-', radix_point_symbol='.', group_split_symbol=None, group_split_count=0, implicit_positive=True, implicit_negative=False))
-
A mutable sequence type of intiger that has a explicitly set base, allowing for specific digit values to be get and set.
Supports any initger base starting at (and including) base 1. The base is presumed to be in the traditional place value format of
value == d[x] * (base ** x)
wherevalue
is the value the digit holds in the intiger,d
is a single digit value form a sequence of digits,base
is the base, andx
is the specific index in question of the intiger.However, base 1 produces inconsistencies with this specific format. Using this logic, one would also presume that the only digit in base 1 is
0
(or whatever relevant "naught" character would be used). This is why the extention of base 1 functionality is done in a child class ofPositionalBasedIntiger
.Base 1, as implemented here, uses both the "naught" (with a value of
0
) and "unity" (with a value of '1') digits, but in a tally system. This also means that the value of any given index of a digit means very little without the context of the rest of the defined digits as well. It is also implemented in such a way that the set digits will always be grouped together, ie. all "unity" digits will be grouped together, starting at the first digit and remaining completely set all the way to the digits index that matches the value of the number represented.For these reason base 1 will have not functionality for functions that set or unset digits, as setting and unsetting digits are not relevant in unary. Attempting to do so will raise either a
BaseInvalidOpperationError
or aBaseValueError
. Deleting digits are still possible, however.Unary numbers are also fully compatible with negative values.
ex.
1111111111 (base 1) == 10 (base 10) 11111 (base 1) == 5 (base 10) 111111 (base 1) == 11 (base 2) 1101101 (base 1) == IMPOSSIBLE (the are unset digits in between the set digits) ^ ^ 000111000 (base 1) == IMPOSSIBLE (the first set digit is not the first digit in the number) ^^^
Effectively: base 1 (uniary) notation treates the value of the number as a sequence of a single type of digit that when counted add up to the value of the number.
NOTE: No functionality of any higher base is nor will modified in this class, making this class a superset of all proper positional based intiger notation formats and uniary.
Also supports customizable notation formats with the optional
digint.notation_format
attribute, including unary.Expand source code
class ExtendedBasedIntiger(PositionalBasedIntiger): """ `ExtendedBasedIntiger` A mutable sequence type of intiger that has a explicitly set base, allowing for specific digit values to be get and set. Supports any initger base starting at (and including) base 1. The base is presumed to be in the traditional place value format of `value == d[x] * (base ** x)` where `value` is the value the digit holds in the intiger, `d` is a single digit value form a sequence of digits, `base` is the base, and `x` is the specific index in question of the intiger. However, base 1 produces inconsistencies with this specific format. Using this logic, one would also presume that the only digit in base 1 is `0` (or whatever relevant "naught" character would be used). This is why the extention of base 1 functionality is done in a child class of `PositionalBasedIntiger`. Base 1, as implemented here, uses both the "naught" (with a value of `0`) and "unity" (with a value of '1') digits, but in a tally system. This also means that the value of any given index of a digit means very little without the context of the rest of the defined digits as well. It is also implemented in such a way that the set digits will always be grouped together, ie. all "unity" digits will be grouped together, starting at the first digit and remaining completely set all the way to the digits index that matches the value of the number represented. For these reason base 1 will have not functionality for functions that set or unset digits, as setting and unsetting digits are not relevant in unary. Attempting to do so will raise either a `BaseInvalidOpperationError` or a `BaseValueError`. Deleting digits are still possible, however. Unary numbers are also fully compatible with negative values. ex. ``` 1111111111 (base 1) == 10 (base 10) 11111 (base 1) == 5 (base 10) 111111 (base 1) == 11 (base 2) 1101101 (base 1) == IMPOSSIBLE (the are unset digits in between the set digits) ^ ^ 000111000 (base 1) == IMPOSSIBLE (the first set digit is not the first digit in the number) ^^^ ``` Effectively: base 1 (uniary) notation treates the value of the number as a sequence of a single type of digit that when counted add up to the value of the number. NOTE: No functionality of any higher base is nor will modified in this class, making this class a superset of all proper positional based intiger notation formats and uniary. Also supports customizable notation formats with the optional `notation_format` attribute, including unary. """ @override def __init__(self, value:Union[int, str, Iterable[Union[int, str]]] = 0, base:int = 10, *, notation_format:Optional[NotationFormat] = DEFAULT_FORMAT ): self.__base:int = 2 super().__init__(0 if base == 1 else value, base, notation_format=notation_format) if base == 1: self.base = 1 if isinstance(value, int): self.x = value elif isinstance(value, str): value = value.lstrip("0") if not all(c == "1" for c in value): raise BaseValueError(f"{value} cannot be represented in base 1") self.x = len(value) @override def copy(self, value:Optional[Union[int, str]] = None, base:Optional[int] = None, notation_format_override:Optional[NotationFormat] = None ) -> 'ExtendedBasedIntiger': """ `copy` Creates a shallow copy of this object. Keyword Arguments: `value` -- When not `None`, will overrides the `x` value of the copy. `base` -- When not `None`, will overrides the `base` of the copy. `notation_format_override` -- When not `None`, will overrides the `notation_format` of the copy. Returns: The copy of the object. """ if notation_format_override is not None: notation_format_override = self.notation_format return ExtendedBasedIntiger(value if value is not None else self.x, base if base is not None else self.base, notation_format = notation_format_override ) __copy__ = copy @override def __deepcopy__(self, _ = None) -> 'ExtendedBasedIntiger': return self.copy(None, None, None if self.notation_format is None else self.notation_format.copy() ) @property @override def base(self) -> int: """ `base` The base of this number. Must be greater than 0. Base 1 is handled particularly differently than other bases. """ return self.__base @base.setter @override def base(self, value:int): if value <= 0: raise BaseValueError() self.__base = value @override def _get_single_digit(self, index:int) -> int: if self.base == 1: index = absindex(index, self.digit_length()) return 1 if index < abs(self.x) else 0 else: return super()._get_single_digit(index) @override def _pop_first(self) -> int: if self.base == 1: self.x -= 1 return 1 else: return super()._pop_first() @override def _mask_value_continuous(self, dindex: int, count: int = 1) -> int: if count <= 0: raise IndexError("The length of a continuous mask must be at least 1") if self.base == 1: return min(abs(self.x) - dindex, count) else: return super()._mask_value_continuous(dindex, count) @override def notate(self, notation_format:Optional[NotationFormat] = None) -> str: if self.base >= 2: return super().notate(notation_format) if notation_format is None: notation_format = self.notation_format if notation_format is None: raise BaseInvalidOpperationError("No format set, cannot notate") relevant_sign = "" if self.x < 0 and not notation_format.implicit_negative: if notation_format.negative_symbol is None: raise ValueError("Explicit negative values require a negative symbol") else: relevant_sign = notation_format.negative_symbol elif self.x > 0 and not notation_format.implicit_positive: if notation_format.positive_symbol is None: raise ValueError("Explicit positive values require a positive symbol") else: relevant_sign = notation_format.positive_symbol if notation_format.unity is None: raise NotationError("Cannot notate base 1 without a digit for unity") return relevant_sign + ((notation_format.unity) * self.x) @overload @override def set_digit(self, index:int, value:Union[int,str]): ... @overload @override def set_digit(self, index:Union[slice,range,Iterable[int]], value:Iterable[Union[int,str]]): ... @override # noqa:301 def set_digit(self, index:Union[int,slice,range,Iterable[int]], value:Union[int,str,Iterable[Union[int,str]]] ): if self.base == 1: raise BaseInvalidOpperationError("Digits cannot be set in base 1") super().set_digit(index, value) # type:ignore[reportCallIssue] @override def unset_digit(self, index:Union[int,slice,range,Iterable[int]]): if self.base == 1: raise BaseInvalidOpperationError("Cannot unset digits in base 1") return super().unset_digit(index) # NOTE: just like python handles it in bit_length, a value of 0 will always have no digits @override def digit_length(self) -> int: if self.base == 1: return abs(self.x) return super().digit_length() @override def insert(self, index:int, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError(f"Cannot insert digits into a base {self.base} number") super().insert(index, value) @override def pop(self, index:int = -1) -> int: if self.base == 1: index = absindex(index, self.digit_length()) self.x -= 1 return 1 else: return super().pop(index) # returns the count of non-zero (non-unset) digits @override def digit_count(self) -> int: if self.base == 1: return abs(self.x) return super().digit_count() @override def digit_shift_left(self, amount:int = 1): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be shifted") super().digit_shift_left(amount) @override def digit_shift_right(self, amount:int = 1): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be shifted") super().digit_shift_right(amount) @override def rstrip(self, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be stripped") super().rstrip(value) @override def lstrip(self, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be stripped") super().lstrip(value) @override def strip(self, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be stripped") super().strip(value) @override def contains(self, value:Union[int, str]) -> bool: if self.base == 1: value = self._ensure_unnotated(value) return (value == 1 and self.x != 0) or (value == 0 and self.x == 0) return super().contains(value)
Ancestors
- PositionalBasedIntiger
- ExtendedUserInt
- UserInt
- typing.SupportsInt
- typing.SupportsFloat
- typing.SupportsAbs
- typing.SupportsComplex
- typing.SupportsRound
- typing.SupportsIndex
- typing.Protocol
- typing.Generic
- collections.abc.Hashable
- collections.abc.MutableSequence
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
Instance variables
prop base : int
-
base
The base of this number. Must be greater than 0. Base 1 is handled particularly differently than other bases.
Expand source code
@property @override def base(self) -> int: """ `base` The base of this number. Must be greater than 0. Base 1 is handled particularly differently than other bases. """ return self.__base
Methods
def contains(self, value: Union[int, str]) ‑> bool
-
contains
Returns true if the digit value appears anywhere in this digit sequence. This will not include leading 0s, but will return true if the tested digit value is
0
and this intiger's value is also 0.Arguments
value – The value to check for.
def copy(self, value: Union[int, str, ForwardRef(None)] = None, base: Optional[int] = None, notation_format_override: Optional[NotationFormat] = None) ‑> ExtendedBasedIntiger
-
copy
Creates a shallow copy of this object.
Keyword Arguments:
value
– When notNone
, will overrides thex
value of the copy.base
– When notNone
, will overrides thebase
of the copy.notation_format_override
– When notNone
, will overrides thedigint.notation_format
of the copy.Returns
The copy of the object.
def digit_count(self) ‑> int
-
digit_count
Similar to
bit_count
, but relitive to the currentbase
. Not to be confused withdigit_length
.Returns
The amount of non-zero (non-unset) digits in the value.
def digit_length(self) ‑> int
-
digit_length
Similar to
bit_length
, but relitive to the currentbase
. Not to be confused withdigit_count
.Returns
The minimum necessary about of digits needed to display the number in full.
def digit_shift_left(self, amount: int = 1)
-
digit_shift_left
Similar to a binary shift left, shifts the value left according to the set base.
Arguments
amount – The amount to shift left. Will shift right when negative.
def digit_shift_right(self, amount: int = 1)
-
digit_shift_right
Similar to a binary shift right, shifts the value right according to the set base.
Arguments
amount – The amount to shift right. Will shift left when negative.
def insert(self, index: int, value: Union[int, str, Iterable[Union[int, str]]])
-
insert
Inserts the given value (or values, following the order in which they are supplied) before the given index. When given multiple values, each value will be inserted before the given index in order.
Arguments
index
– The index (or indexes) to be inserted before.value
– The value (or values) to insert. def lstrip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
rstrip
Removes the given digit (or digits) from the left hand (greatest place value) spot. Works similarly to
str.lstrip
, except for the fact that whenvalue
is a single string (not a iterable of strings) it will be treated as a single digit instead of a iterable of digits. This will not strip any leading0
digit values, as these are already not notated by default nor would effect the digit length of this intiger.Arguments
value – The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit.
def notate(self, notation_format: Optional[NotationFormat] = None) ‑> str
-
notate
Notates the intiger, using the given notation format if possible, or thedigint.notation_format
set in the object's attributes if the paramater is not set.Keyword Arguments: notation_format – A notation format to use over the one set in
self.notation_format
, if notNone
.Raises
NotationError
- Raised when both the argument and attribute
digint.notation_format
areNone
; or when other errors are raised during notation.
Returns
The final notation of the intiger.
def pop(self, index: int = -1) ‑> int
-
pop
Gets the value at the given index while popping it.
Keyword Arguments: index – The target index to pop. Defaults to -1.
Returns
The value at the given index before removal.
def rstrip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
rstrip
Removes the given digit (or digits) from the right hand (units) spot. Works similarly to
str.rstrip
, except for the fact that whenvalue
is a single string (not a iterable of strings) it will be treated as a single digit instead of a iterable of digits.Arguments
value – The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit.
def set_digit(self, index: Union[int, slice, range, Iterable[int]], value: Union[int, str, Iterable[Union[int, str]]])
-
set_digit
Sets the digit (or digits) at the given index (or indexes) to the given value (or values). With multiple indexes and, there must be a matching quantity of values to set at those indexes.
Arguments
index
– The index (or indexes) to set.value
– The value (or values) to set the index (or indexes) to.Raises
ValueError
: Raised when the given value is out of bounds of the currentbase
. def strip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
rstrip
Removes the given digit (or digits) from both sides. Works similarly to
str.strip
, except for the fact that whenvalue
is a single string (not a iterable of strings) it will be treated as a single digit instead of a iterable of digits. This will not strip any leading0
digit values, as these are already not notated by default nor would effect the digit length of this intiger.Arguments
value – The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit.
def unset_digit(self, index: Union[int, slice, range, Iterable[int]])
-
unset_digit
Unsets (set to 0) the value at the given index (or indexes).
Arguments
index
– The index (or indexes) digit to be unset.
class digitint (value: Union[int, str, Iterable[Union[int, str]]] = 0, base: int = 10, *, notation_format: Optional[NotationFormat] = NotationFormat(value_symbols=('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'), undefined_symbol='?', positive_symbol='+', negative_symbol='-', radix_point_symbol='.', group_split_symbol=None, group_split_count=0, implicit_positive=True, implicit_negative=False))
-
A mutable sequence type of intiger that has a explicitly set base, allowing for specific digit values to be get and set.
Supports any initger base starting at (and including) base 1. The base is presumed to be in the traditional place value format of
value == d[x] * (base ** x)
wherevalue
is the value the digit holds in the intiger,d
is a single digit value form a sequence of digits,base
is the base, andx
is the specific index in question of the intiger.However, base 1 produces inconsistencies with this specific format. Using this logic, one would also presume that the only digit in base 1 is
0
(or whatever relevant "naught" character would be used). This is why the extention of base 1 functionality is done in a child class ofPositionalBasedIntiger
.Base 1, as implemented here, uses both the "naught" (with a value of
0
) and "unity" (with a value of '1') digits, but in a tally system. This also means that the value of any given index of a digit means very little without the context of the rest of the defined digits as well. It is also implemented in such a way that the set digits will always be grouped together, ie. all "unity" digits will be grouped together, starting at the first digit and remaining completely set all the way to the digits index that matches the value of the number represented.For these reason base 1 will have not functionality for functions that set or unset digits, as setting and unsetting digits are not relevant in unary. Attempting to do so will raise either a
BaseInvalidOpperationError
or aBaseValueError
. Deleting digits are still possible, however.Unary numbers are also fully compatible with negative values.
ex.
1111111111 (base 1) == 10 (base 10) 11111 (base 1) == 5 (base 10) 111111 (base 1) == 11 (base 2) 1101101 (base 1) == IMPOSSIBLE (the are unset digits in between the set digits) ^ ^ 000111000 (base 1) == IMPOSSIBLE (the first set digit is not the first digit in the number) ^^^
Effectively: base 1 (uniary) notation treates the value of the number as a sequence of a single type of digit that when counted add up to the value of the number.
NOTE: No functionality of any higher base is nor will modified in this class, making this class a superset of all proper positional based intiger notation formats and uniary.
Also supports customizable notation formats with the optional
digint.notation_format
attribute, including unary.Expand source code
class ExtendedBasedIntiger(PositionalBasedIntiger): """ `ExtendedBasedIntiger` A mutable sequence type of intiger that has a explicitly set base, allowing for specific digit values to be get and set. Supports any initger base starting at (and including) base 1. The base is presumed to be in the traditional place value format of `value == d[x] * (base ** x)` where `value` is the value the digit holds in the intiger, `d` is a single digit value form a sequence of digits, `base` is the base, and `x` is the specific index in question of the intiger. However, base 1 produces inconsistencies with this specific format. Using this logic, one would also presume that the only digit in base 1 is `0` (or whatever relevant "naught" character would be used). This is why the extention of base 1 functionality is done in a child class of `PositionalBasedIntiger`. Base 1, as implemented here, uses both the "naught" (with a value of `0`) and "unity" (with a value of '1') digits, but in a tally system. This also means that the value of any given index of a digit means very little without the context of the rest of the defined digits as well. It is also implemented in such a way that the set digits will always be grouped together, ie. all "unity" digits will be grouped together, starting at the first digit and remaining completely set all the way to the digits index that matches the value of the number represented. For these reason base 1 will have not functionality for functions that set or unset digits, as setting and unsetting digits are not relevant in unary. Attempting to do so will raise either a `BaseInvalidOpperationError` or a `BaseValueError`. Deleting digits are still possible, however. Unary numbers are also fully compatible with negative values. ex. ``` 1111111111 (base 1) == 10 (base 10) 11111 (base 1) == 5 (base 10) 111111 (base 1) == 11 (base 2) 1101101 (base 1) == IMPOSSIBLE (the are unset digits in between the set digits) ^ ^ 000111000 (base 1) == IMPOSSIBLE (the first set digit is not the first digit in the number) ^^^ ``` Effectively: base 1 (uniary) notation treates the value of the number as a sequence of a single type of digit that when counted add up to the value of the number. NOTE: No functionality of any higher base is nor will modified in this class, making this class a superset of all proper positional based intiger notation formats and uniary. Also supports customizable notation formats with the optional `notation_format` attribute, including unary. """ @override def __init__(self, value:Union[int, str, Iterable[Union[int, str]]] = 0, base:int = 10, *, notation_format:Optional[NotationFormat] = DEFAULT_FORMAT ): self.__base:int = 2 super().__init__(0 if base == 1 else value, base, notation_format=notation_format) if base == 1: self.base = 1 if isinstance(value, int): self.x = value elif isinstance(value, str): value = value.lstrip("0") if not all(c == "1" for c in value): raise BaseValueError(f"{value} cannot be represented in base 1") self.x = len(value) @override def copy(self, value:Optional[Union[int, str]] = None, base:Optional[int] = None, notation_format_override:Optional[NotationFormat] = None ) -> 'ExtendedBasedIntiger': """ `copy` Creates a shallow copy of this object. Keyword Arguments: `value` -- When not `None`, will overrides the `x` value of the copy. `base` -- When not `None`, will overrides the `base` of the copy. `notation_format_override` -- When not `None`, will overrides the `notation_format` of the copy. Returns: The copy of the object. """ if notation_format_override is not None: notation_format_override = self.notation_format return ExtendedBasedIntiger(value if value is not None else self.x, base if base is not None else self.base, notation_format = notation_format_override ) __copy__ = copy @override def __deepcopy__(self, _ = None) -> 'ExtendedBasedIntiger': return self.copy(None, None, None if self.notation_format is None else self.notation_format.copy() ) @property @override def base(self) -> int: """ `base` The base of this number. Must be greater than 0. Base 1 is handled particularly differently than other bases. """ return self.__base @base.setter @override def base(self, value:int): if value <= 0: raise BaseValueError() self.__base = value @override def _get_single_digit(self, index:int) -> int: if self.base == 1: index = absindex(index, self.digit_length()) return 1 if index < abs(self.x) else 0 else: return super()._get_single_digit(index) @override def _pop_first(self) -> int: if self.base == 1: self.x -= 1 return 1 else: return super()._pop_first() @override def _mask_value_continuous(self, dindex: int, count: int = 1) -> int: if count <= 0: raise IndexError("The length of a continuous mask must be at least 1") if self.base == 1: return min(abs(self.x) - dindex, count) else: return super()._mask_value_continuous(dindex, count) @override def notate(self, notation_format:Optional[NotationFormat] = None) -> str: if self.base >= 2: return super().notate(notation_format) if notation_format is None: notation_format = self.notation_format if notation_format is None: raise BaseInvalidOpperationError("No format set, cannot notate") relevant_sign = "" if self.x < 0 and not notation_format.implicit_negative: if notation_format.negative_symbol is None: raise ValueError("Explicit negative values require a negative symbol") else: relevant_sign = notation_format.negative_symbol elif self.x > 0 and not notation_format.implicit_positive: if notation_format.positive_symbol is None: raise ValueError("Explicit positive values require a positive symbol") else: relevant_sign = notation_format.positive_symbol if notation_format.unity is None: raise NotationError("Cannot notate base 1 without a digit for unity") return relevant_sign + ((notation_format.unity) * self.x) @overload @override def set_digit(self, index:int, value:Union[int,str]): ... @overload @override def set_digit(self, index:Union[slice,range,Iterable[int]], value:Iterable[Union[int,str]]): ... @override # noqa:301 def set_digit(self, index:Union[int,slice,range,Iterable[int]], value:Union[int,str,Iterable[Union[int,str]]] ): if self.base == 1: raise BaseInvalidOpperationError("Digits cannot be set in base 1") super().set_digit(index, value) # type:ignore[reportCallIssue] @override def unset_digit(self, index:Union[int,slice,range,Iterable[int]]): if self.base == 1: raise BaseInvalidOpperationError("Cannot unset digits in base 1") return super().unset_digit(index) # NOTE: just like python handles it in bit_length, a value of 0 will always have no digits @override def digit_length(self) -> int: if self.base == 1: return abs(self.x) return super().digit_length() @override def insert(self, index:int, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError(f"Cannot insert digits into a base {self.base} number") super().insert(index, value) @override def pop(self, index:int = -1) -> int: if self.base == 1: index = absindex(index, self.digit_length()) self.x -= 1 return 1 else: return super().pop(index) # returns the count of non-zero (non-unset) digits @override def digit_count(self) -> int: if self.base == 1: return abs(self.x) return super().digit_count() @override def digit_shift_left(self, amount:int = 1): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be shifted") super().digit_shift_left(amount) @override def digit_shift_right(self, amount:int = 1): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be shifted") super().digit_shift_right(amount) @override def rstrip(self, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be stripped") super().rstrip(value) @override def lstrip(self, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be stripped") super().lstrip(value) @override def strip(self, value:Union[int,str,Iterable[Union[int,str]]]): if self.base == 1: raise BaseInvalidOpperationError("This base cannot be stripped") super().strip(value) @override def contains(self, value:Union[int, str]) -> bool: if self.base == 1: value = self._ensure_unnotated(value) return (value == 1 and self.x != 0) or (value == 0 and self.x == 0) return super().contains(value)
Ancestors
- PositionalBasedIntiger
- ExtendedUserInt
- UserInt
- typing.SupportsInt
- typing.SupportsFloat
- typing.SupportsAbs
- typing.SupportsComplex
- typing.SupportsRound
- typing.SupportsIndex
- typing.Protocol
- typing.Generic
- collections.abc.Hashable
- collections.abc.MutableSequence
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
Instance variables
prop base : int
-
base
The base of this number. Must be greater than 0. Base 1 is handled particularly differently than other bases.
Expand source code
@property @override def base(self) -> int: """ `base` The base of this number. Must be greater than 0. Base 1 is handled particularly differently than other bases. """ return self.__base
prop limit_high : Optional[int]
-
Inherited from:
PositionalBasedIntiger
.limit_high
limit_high …
prop limit_low : Optional[int]
-
Inherited from:
PositionalBasedIntiger
.limit_low
limit_low …
var on_changed
-
Inherited from:
PositionalBasedIntiger
.on_changed
on_changed
… prop radix : int
-
Inherited from:
PositionalBasedIntiger
.radix
radix …
prop sign : int
-
Inherited from:
PositionalBasedIntiger
.sign
sign
… prop x : int
-
Inherited from:
PositionalBasedIntiger
.x
x
…
Methods
def bit_count(self) ‑> int
-
Inherited from:
PositionalBasedIntiger
.bit_count
bit_count
… def bit_length(self) ‑> int
-
Inherited from:
PositionalBasedIntiger
.bit_length
bit_count
… def contains(self, value: Union[int, str]) ‑> bool
-
Inherited from:
PositionalBasedIntiger
.contains
contains
… def copy(self, value: Union[int, str, ForwardRef(None)] = None, base: Optional[int] = None, notation_format_override: Optional[NotationFormat] = None) ‑> ExtendedBasedIntiger
-
copy
Creates a shallow copy of this object.
Keyword Arguments:
value
– When notNone
, will overrides thex
value of the copy.base
– When notNone
, will overrides thebase
of the copy.notation_format_override
– When notNone
, will overrides thedigint.notation_format
of the copy.Returns
The copy of the object.
def delete_digit(self, index: Union[int, slice, range, Iterable[int]])
-
Inherited from:
PositionalBasedIntiger
.delete_digit
delete_digit
… def digit_count(self) ‑> int
-
Inherited from:
PositionalBasedIntiger
.digit_count
digit_count
… def digit_length(self) ‑> int
-
Inherited from:
PositionalBasedIntiger
.digit_length
digit_length
… def digit_rotate_left(self, amount: int = 1)
-
Inherited from:
PositionalBasedIntiger
.digit_rotate_left
digit_rotate_left
… def digit_rotate_right(self, amount: int = 1)
-
Inherited from:
PositionalBasedIntiger
.digit_rotate_right
digit_rotate_right
… def digit_shift_left(self, amount: int = 1)
-
Inherited from:
PositionalBasedIntiger
.digit_shift_left
digit_shift_left
… def digit_shift_right(self, amount: int = 1)
-
Inherited from:
PositionalBasedIntiger
.digit_shift_right
digit_shift_right
… def fixed_sign_and(self, value: int) ‑> int
-
Inherited from:
PositionalBasedIntiger
.fixed_sign_and
fixed_sign_and
… def fixed_sign_invert(self) ‑> int
-
Inherited from:
PositionalBasedIntiger
.fixed_sign_invert
fixed_sign_invert
… def fixed_sign_or(self, value: int) ‑> int
-
Inherited from:
PositionalBasedIntiger
.fixed_sign_or
fixed_sign_or
… def fixed_sign_xor(self, value: int) ‑> int
-
Inherited from:
PositionalBasedIntiger
.fixed_sign_xor
fixed_sign_xor
… def get_digit(self, index: Union[int, slice, range, Iterable[int]]) ‑> Union[int, List[int]]
-
Inherited from:
PositionalBasedIntiger
.get_digit
get_digit
… def insert(self, index: int, value: Union[int, str, Iterable[Union[int, str]]])
-
Inherited from:
PositionalBasedIntiger
.insert
insert
… def is_integer(self) ‑> bool
-
Inherited from:
PositionalBasedIntiger
.is_integer
is_integer
… def iter_digits(self, at_least: int = 0) ‑> Iterator[int]
-
Inherited from:
PositionalBasedIntiger
.iter_digits
iter_digits
Returns an iterable that iterates through the digit values of the integer, starting at the units spot. Will iterate 0 when all other … def iter_symbols(self, at_least: int = 1) ‑> Iterator[str]
-
Inherited from:
PositionalBasedIntiger
.iter_symbols
iter_symbols
… def lstrip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
Inherited from:
PositionalBasedIntiger
.lstrip
rstrip
… def mask(self, index: Union[int, slice, range, Iterable[int]]) ‑> int
-
Inherited from:
PositionalBasedIntiger
.mask
mask
… def notate(self, notation_format: Optional[NotationFormat] = None) ‑> str
-
Inherited from:
PositionalBasedIntiger
.notate
notate
Notates the intiger, using the given notation format if possible, or thedigint.notation_format
set in the object's attributes if the paramater is … def pop(self, index: int = -1) ‑> int
-
Inherited from:
PositionalBasedIntiger
.pop
pop
… def reversed_iter_digits(self, at_least: int = 0) ‑> Iterator[int]
-
Inherited from:
PositionalBasedIntiger
.reversed_iter_digits
reversed_iter_digits
Returns an iterable that iterates through the digit values of the integer, ending at the units spot. Will iterate 0 when all … def reversed_iter_symbols(self, at_least: int = 1) ‑> Iterator[str]
-
Inherited from:
PositionalBasedIntiger
.reversed_iter_symbols
reversed_iter_symbols
… def rstrip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
Inherited from:
PositionalBasedIntiger
.rstrip
rstrip
… def set_digit(self, index: Union[int, slice, range, Iterable[int]], value: Union[int, str, Iterable[Union[int, str]]])
-
Inherited from:
PositionalBasedIntiger
.set_digit
set_digit
… def strip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
Inherited from:
PositionalBasedIntiger
.strip
rstrip
… def to_bytes(self, length:
, byteorder: Literal['little', 'big'], *, signed: bool = False) ‑> bytes -
Inherited from:
PositionalBasedIntiger
.to_bytes
to_bytes
… def unset_digit(self, index: Union[int, slice, range, Iterable[int]])
-
Inherited from:
PositionalBasedIntiger
.unset_digit
unset_digit
…
class NotationFormat (*value_symbols: str, undefined_symbol: Optional[str] = None, positive_symbol: Optional[str] = None, negative_symbol: Optional[str] = None, radix_point_symbol: Optional[str] = None, group_split_symbol: Optional[str] = None, group_split_count: int = 0, implicit_positive: bool = False, implicit_negative: bool = False)
-
A dataclass that holds common notation formating information.
Expand source code
@dataclass(init=False) class NotationFormat(SequenceABC, HashableABC): """ `NotationFormat` A dataclass that holds common notation formating information. """ value_symbols:Tuple[str, ...] = tuple() undefined_symbol:Optional[str] = None positive_symbol:Optional[str] = None negative_symbol:Optional[str] = None radix_point_symbol:Optional[str] = None group_split_symbol:Optional[str] = None group_split_count:int = 3 implicit_positive:bool = False implicit_negative:bool = False def __init__(self, *value_symbols:str, undefined_symbol:Optional[str] = None, positive_symbol:Optional[str] = None, negative_symbol:Optional[str] = None, radix_point_symbol:Optional[str] = None, group_split_symbol:Optional[str] = None, group_split_count:int = 0, implicit_positive:bool = False, implicit_negative:bool = False ): self.__frozen:bool = False self.value_symbols:Tuple[str, ...] = value_symbols self.undefined_symbol:Optional[str] = undefined_symbol self.negative_symbol:Optional[str] = negative_symbol self.positive_symbol:Optional[str] = positive_symbol self.radix_point_symbol:Optional[str] = radix_point_symbol self.group_split_symbol:Optional[str] = group_split_symbol self.group_split_count:int = group_split_count self.implicit_positive:bool = implicit_positive self.implicit_negative:bool = implicit_negative self.__frozen = True def __setattribute__(self, name: str, value: Any): if self.__frozen: raise FrozenInstanceError(value, name, self) return super().__setattr__(name, value) @property def unity(self) -> Optional[str]: """ `unity` Returns: The 'unity' symbol (the symbol associated with the value of 1), if defined, from the `value_symbols`. If not defined, returns `None`. """ return self.value_symbols[1] if len(self.value_symbols) >= 1 else None @property def naught(self) -> Optional[str]: """ `naught` Returns: The 'naught' symbol (the symbol associated with the value of 0), if defined, from the `value_symbols`. If not defined, returns `None`. """ return self.value_symbols[0] if len(self.value_symbols) >= 0 else None def get_value(self, symbol:str) -> Optional[int]: """ `get_value` Looks for the first instance of the given symbol in the `value_symbols`. Arguments: `symbol` -- The symbol to look up. Returns: The index (and therefroe the value) of the symbol in `value_symbols` if possible, otherwise returns `None`. """ return None if symbol not in self.value_symbols else self.value_symbols.index(symbol) @overload def __getitem__(self, index:int) -> str: ... @overload def __getitem__(self, index:slice) -> Tuple[str, ...]: ... def __getitem__(self, index:Union[int, slice]) -> Union[str, Tuple[str, ...]]: # noqa:301 return self.value_symbols[index] def get_digit(self, index:int) -> Optional[str]: """ `get_digit` Looks for the symbol for the given value, if possible`. Arguments: `index` -- The index (the digit's value) to find the symbol of. Returns: The symbol of the given value from `value_symbols` if possible, otherwise returns `None`. """ if index < 0 or index >= len(self.value_symbols): return self.undefined_symbol else: return self.value_symbols[index] def __len__(self): return len(self.value_symbols) def __iter__(self) -> Iterator[str]: return iter(self.value_symbols) def __reverse__(self) -> Iterator[str]: return reversed(self.value_symbols) def copy(self, *_) -> 'NotationFormat': """ `copy` Returns a deep copy of the object. """ return NotationFormat(*self.value_symbols, undefined_symbol = self.undefined_symbol, positive_symbol = self.positive_symbol, negative_symbol = self.negative_symbol, radix_point_symbol = self.radix_point_symbol, group_split_symbol = self.group_split_symbol, group_split_count = self.group_split_count, implicit_positive = self.implicit_positive, implicit_negative = self.implicit_negative ) __copy__ = copy __deepcopy__ = copy def __hash__(self) -> int: return hash(asdict(self))
Ancestors
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
- collections.abc.Hashable
Class variables
var group_split_count : int
var group_split_symbol : Optional[str]
var implicit_negative : bool
var implicit_positive : bool
var negative_symbol : Optional[str]
var positive_symbol : Optional[str]
var radix_point_symbol : Optional[str]
var undefined_symbol : Optional[str]
var value_symbols : Tuple[str, ...]
Instance variables
prop naught : Optional[str]
-
naught
Returns
The 'naught' symbol (the symbol associated with the value of 0), if defined, from the
value_symbols
. If not defined, returnsNone
.Expand source code
@property def naught(self) -> Optional[str]: """ `naught` Returns: The 'naught' symbol (the symbol associated with the value of 0), if defined, from the `value_symbols`. If not defined, returns `None`. """ return self.value_symbols[0] if len(self.value_symbols) >= 0 else None
prop unity : Optional[str]
-
unity
Returns
The 'unity' symbol (the symbol associated with the value of 1), if defined, from the
value_symbols
. If not defined, returnsNone
.Expand source code
@property def unity(self) -> Optional[str]: """ `unity` Returns: The 'unity' symbol (the symbol associated with the value of 1), if defined, from the `value_symbols`. If not defined, returns `None`. """ return self.value_symbols[1] if len(self.value_symbols) >= 1 else None
Methods
def copy(self, *_) ‑> NotationFormat
-
copy
Returns a deep copy of the object.
def get_digit(self, index: int) ‑> Optional[str]
-
get_digit
Looks for the symbol for the given value, if possible`.
Arguments
index
– The index (the digit's value) to find the symbol of.Returns
The symbol of the given value from
value_symbols
if possible, otherwise returnsNone
. def get_value(self, symbol: str) ‑> Optional[int]
-
get_value
Looks for the first instance of the given symbol in the
value_symbols
.Arguments
symbol
– The symbol to look up.Returns
The index (and therefroe the value) of the symbol in
value_symbols
if possible, otherwise returnsNone
.
class PositionalBasedIntiger (value: Union[int, str, Iterable[Union[int, str]], bytes, bytearray, memoryview] = 0, base: int = 10, *, notation_format: Optional[NotationFormat] = NotationFormat(value_symbols=('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'), undefined_symbol='?', positive_symbol='+', negative_symbol='-', radix_point_symbol='.', group_split_symbol=None, group_split_count=0, implicit_positive=True, implicit_negative=False))
-
A mutable sequence type of intiger that has a explicitly set base, allowing for specific digit values to be get and set.
Supports any initger base starting at binary (base 2). These bases are presumed to be in the traditional place value format of
value == d[x] * (base ** x)
wherevalue
is the value the digit holds in the intiger,d
is a single digit value form a sequence of digits,base
is the base, andx
is the specific index in question of the intiger.Supports many operators and methods that built in integers suport, casting the type back into a default intiger type when possible.
Also supports customizable notation formats with the optional
digint.notation_format
attribute.Expand source code
class PositionalBasedIntiger(*tuple(__POSITIONAL_BASED_INT_BASES)): """ `PositionalBasedIntiger` A mutable sequence type of intiger that has a explicitly set base, allowing for specific digit values to be get and set. Supports any initger base starting at binary (base 2). These bases are presumed to be in the traditional place value format of `value == d[x] * (base ** x)` where `value` is the value the digit holds in the intiger, `d` is a single digit value form a sequence of digits, `base` is the base, and `x` is the specific index in question of the intiger. Supports many operators and methods that built in integers suport, casting the type back into a default intiger type when possible. Also supports customizable notation formats with the optional `notation_format` attribute. """ def __init__(self, value:Union[int, str, Iterable[Union[int, str]], bytes, bytearray, memoryview] = 0, base:int = 10, *, notation_format:Optional[NotationFormat] = DEFAULT_FORMAT ): super().__init__(0) self.__base:int = 2 self.x = 0 self.base = base self.notation_format:Optional[NotationFormat] = notation_format if isinstance(value, int): self.x = value elif isinstance(value, str): self.x = int(value, base) else: for digit_value in value: digit_value = self._ensure_unnotated(digit_value) if digit_value >= base: raise ValueError(f"Digit of value {digit_value} isn't possible in base {base}") self.x = (self.x * base) + digit_value def copy(self, value:Optional[Union[int, str]] = None, base:Optional[int] = None, notation_format_override:Optional[NotationFormat] = None ) -> 'PositionalBasedIntiger': """ `copy` Creates a shallow copy of this object. Keyword Arguments: value -- When not `None`, will overrides the `x` value of the copy. base -- When not `None`, will overrides the `base` of the copy. notation_format_override -- When not `None`, will overrides the `notation_format` of the copy. Returns: The copy of the object. """ if notation_format_override is not None: notation_format_override = self.notation_format return PositionalBasedIntiger(value if value is not None else self.x, base if base is not None else self.base, notation_format = notation_format_override ) __copy__ = copy def __deepcopy__(self, _ = None) -> 'PositionalBasedIntiger': return self.copy(None, None, None if self.notation_format is None else self.notation_format.copy() ) @property def base(self) -> int: """ `base` The base of the intiger. Must be at or above 2, as this class does not support any non-standard bases. """ return self.__base @base.setter def base(self, value:int): if value < 2: raise ValueError("Invalid base", value) self.__base = value @property def radix(self) -> int: """ radix Returns: The absolute value of the base. Will always return `base` when used in a `PositionalBasedIntiger`, but may differ when using with a extended type. """ return abs(self.base) def _ensure_notated(self, value:Union[int,str]) -> str: if self.notation_format is None: raise NotationError("Cannot reference a symbol without a notation format") if isinstance(value, str): return value else: dig = self.notation_format.get_digit(value) if dig is None: raise NotationError(f"Could not find digit for {value} in current notation format") return dig def _ensure_unnotated(self, value:Union[int,str]) -> int: if self.notation_format is None: raise NotationError("Cannot reference a symbol without a notation format") if isinstance(value, int): return value v = self.notation_format.get_value(value) if v is None: raise NotationError(f"Given symbol '{value}' not found in current notation format") return v def _get_single_digit(self, index:int) -> int: index = absindex(index, self.digit_length()) if self.base == 2: return (abs(self.x) >> index) % (0b1 << 1) else: return (abs(self.x) // (self.base ** index)) % self.base # this pops the digit in the units spot, # effectively shifts left once while returning units shifted out # slightly faster than the arbitrary pop method def _pop_first(self) -> int: dm = divmod(self.x, self.base) self.x = dm[0] return dm[1] # this pushes a value into the units place # effectively shifts right while appending a new value to the units # slightly faster than the arbitrary insert method def _prepend(self, value:Union[int,str]): value = self._ensure_unnotated(value) if value < 0 or value >= self.base: raise ValueError("Digit value out of bounds of base") if self.sign == -1: value *= -1 self.x = (self.x * self.base) + value # effectively, this returns a continuous sequence # form the intiger with its place value still intact def _mask_value_continuous(self, dindex:int, count:int = 1) -> int: if count <= 0: raise IndexError("The length of a continuous mask must be at least 1") dindex = absindex(dindex, self.digit_length()) if self.base == 2: # binary optimisable return abs(self.x) & (((0b1 << (count - 1)) - 1) << dindex) else: pv1 = self.base ** dindex pv2 = pv1 * (self.base ** count) # aka ```self.base ** (dindex + count)``` return (abs(self.x) % pv2) - (abs(self.x) % pv1) def iter_digits(self, at_least:int = 0) -> Iterator[int]: """ `iter_digits` Returns an iterable that iterates through the digit values of the integer, starting at the units spot. Will iterate 0 when all other digits are already iterated. Keyword Arguments: `at_least` -- Ensures that at least the given amount of digits are iterated, if above 1. Returns: An iterator that returns the digit values, starting at the units spot. Yields: The digits of the intiger, starting at the units spot. """ indexes = range(max(self.digit_length(), at_least)) return (self._get_single_digit(i) for i in indexes) __iter__ = iter_digits def reversed_iter_digits(self, at_least:int = 0) -> Iterator[int]: """ `reversed_iter_digits` Returns an iterable that iterates through the digit values of the integer, ending at the units spot. Will iterate 0 when all other digits are already iterated. Keyword Arguments: `at_least` -- Ensures that at least the given amount of digits are iterated, if above 1. Returns: An iterator that returns the digit values, ending at the units spot. Yields: The digits of the intiger, ending at the units spot. """ indexes = range(max(self.digit_length(), at_least)-1, -1, -1) return (self._get_single_digit(i) for i in indexes) __reverse__ = reversed_iter_digits def __bytes__(self): return bytes(self.iter_digits(0)) def iter_symbols(self, at_least:int = 1) -> Iterator[str]: """ `iter_symbols` Iterate the digit symbols starting at the units spot. When intending to use iteration for notation, it's suggested to use `reversed_iter_symbols` to avoid odering errors. Keyword Arguments: `at_least` -- ensures that at least the given amount of symbols are returned. Defaults to 1. Returns: An iterator of symbols. Yields: Digit symdols, starting at the units spot. """ return (self._ensure_notated(x) for x in self.iter_digits(at_least)) def reversed_iter_symbols(self, at_least:int = 1) -> Iterator[str]: """ `reversed_iter_symbols` Iterate the digit symbols ending at the units spot. Intending to be used for notation purposes, as the ordering for string notation is correct. Keyword Arguments: `at_least` -- ensures that at least the given amount of symbols are returned. Defaults to 1. Returns: An iterator of symbols. Yields: Digit symdols, ending at the units spot. """ return (self._ensure_notated(x) for x in self.reversed_iter_digits(at_least)) def notate(self, notation_format:Optional[NotationFormat] = None) -> str: """ `notate` Notates the intiger, using the given notation format if possible, or the `notation_format` set in the object's attributes if the paramater is not set. Keyword Arguments: notation_format -- A notation format to use over the one set in `self.notation_format`, if not `None`. Raises: NotationError: Raised when both the argument and attribute `notation_format` are `None`; or when other errors are raised during notation. Returns: The final notation of the intiger. """ if notation_format is None: notation_format = self.notation_format if notation_format is None: raise NotationError("No format set, cannot notate") relevant_sign = "" if self.x < 0 and not notation_format.implicit_negative: if notation_format.negative_symbol is None: raise NotationError("Explicit negative values require a negative symbol") else: relevant_sign = notation_format.negative_symbol elif self.x > 0 and not notation_format.implicit_positive: if notation_format.positive_symbol is None: raise NotationError("Explicit positive values require a positive symbol") else: relevant_sign = notation_format.positive_symbol group_joint = "" if notation_format.group_split_symbol is not None: group_joint = notation_format.group_split_symbol group_count = notation_format.group_split_count if group_joint != "" and group_count > 0: groups = list(self.iter_symbols()) group_indexes = range(0, self.digit_length(), group_count) groups = [''.join(groups[i:i+group_count])[::-1] for i in group_indexes] groups = groups[::-1] else: groups = self.reversed_iter_symbols() return relevant_sign + group_joint.join(groups) __str__ = notate __repr__ = notate @overload def get_digit(self, index:int) -> int: ... @overload def get_digit(self, index:Union[slice,range,Iterable[int]]) -> List[int]: ... def get_digit(self, # noqa:301 index:Union[int,slice,range,Iterable[int]] ) -> Union[int,List[int]]: """ `get_digit` Gets the specific digit's (or digits's) value at the specific index (or indexes). Arguments: `index` -- The index (or indexes) in question. Returns: The value (or values, contained in a `List`) found at the index. """ if isinstance(index, int): return self._get_single_digit(index) if isinstance(index, slice): index = slice_to_range(index, self.digit_length()) return list(self._get_single_digit(absindex(i, self.digit_length())) for i in index) __getitem__ = get_digit @overload def set_digit(self, index:int, value:Union[int,str]): ... @overload def set_digit(self, index:Union[slice,range,Iterable[int]], value:Iterable[Union[int,str]]): ... def set_digit(self, # noqa:301 index:Union[int,slice,range,Iterable[int]], value:Union[int,str,Iterable[Union[int,str]]] ): """ `set_digit` Sets the digit (or digits) at the given index (or indexes) to the given value (or values). With multiple indexes and, there must be a matching quantity of values to set at those indexes. Arguments: `index` -- The index (or indexes) to set. `value` -- The value (or values) to set the index (or indexes) to. Raises: `ValueError`: Raised when the given value is out of bounds of the current `base`. """ if isinstance(value, Iterable): value = (self._ensure_unnotated(v) for v in value) else: value = self._ensure_unnotated(value) if isinstance(value, int): value = [value] else: value = cast(List[int], list(value)) if isinstance(index, int): index = (index, ) elif isinstance(index, slice): index = slice_to_range(index, self.digit_length()) sign = self.sign self.x = abs(self.x) for i, v in zip(index, value): if v < 0 or v >= self.base: raise ValueError("Digit value out of bounds of base") i = absindex(i, self.digit_length()) if self.base == 2: # binary optimisable if v == 1: self.x |= (0b1 << i) else: self.x &= ~(0b1 << i) else: pv = self.base ** i mask = self._mask_value_continuous(i) self.x = (self.x - mask) + (v * pv) if sign != 0: self.x *= sign __setitem__ = set_digit def delete_digit(self, index:Union[int,slice,range,Iterable[int]]): """ `delete_digit` Removes the value at the given index (or indexes). Arguments: `index` -- The index (or indexes) digit to be removed. """ if isinstance(index, slice): index = slice_to_range(index, self.digit_length()) if isinstance(index, int): index = (index, ) for i in sorted(index, reverse=True): self.pop(i) __delitem__ = delete_digit def unset_digit(self, index:Union[int,slice,range,Iterable[int]]): """ `unset_digit` Unsets (set to 0) the value at the given index (or indexes). Arguments: `index` -- The index (or indexes) digit to be unset. """ if isinstance(index, slice): index = slice_to_range(index, self.digit_length()) if isinstance(index, int): index = (index, ) sign = self.sign self.x = abs(self.x) if self.base == 2: # binary optimization for i in index: i = absindex(i, self.digit_length()) self.x = (self.x >> 1) << 1 else: for i in index: i = absindex(i, self.digit_length()) self.x -= self._mask_value_continuous(i) if sign != 0: self.x *= sign # NOTE: just like python handles it in bit_length, a value of 0 will always have no digits def digit_length(self) -> int: """ `digit_length` Similar to `bit_length`, but relitive to the current `base`. Not to be confused with `digit_count`. Returns: The minimum necessary about of digits needed to display the number in full. """ if self.x == 0: return 0 if self.base == 2: return abs(self.x).bit_length() else: c = 0 v = abs(self.x) while v != 0: c += 1 v //= self.base return c __len__ = digit_length def insert(self, index:int, value:Union[int,str,Iterable[Union[int,str]]]): """ `insert` Inserts the given value (or values, following the order in which they are supplied) before the given index. When given multiple values, each value will be inserted before the given index in order. Arguments: `index` -- The index (or indexes) to be inserted before. `value` -- The value (or values) to insert. """ # not the current length, but the length this will have after the insert index = absindex(index, self.digit_length() + 1) if isinstance(value, Iterable): value = (self._ensure_unnotated(v) for v in value) else: value = self._ensure_unnotated(value) if isinstance(value, int): value = (value, ) for v in value: if v < 0 or v >= self.base: raise ValueError("Digit value out of bounds of base") restore_sign = self.sign self.x = abs(self.x) if index == 0: self._prepend(v) continue high = self.copy() high.unset_digit(slice(0, index)) if high.x != 0: self.x -= high.x high.x *= high.base self.x += high.x v = self.copy(v) v.x *= (v.base ** (index)) self.x += v.x self.x *= restore_sign def pop(self, index:int = -1) -> int: """ `pop` Gets the value at the given index while popping it. Keyword Arguments: index -- The target index to pop. Defaults to -1. Returns: The value at the given index before removal. """ index = absindex(index, self.digit_length()) if index == 0: return self._pop_first() popped = self._get_single_digit(index) high = self.copy() self.unset_digit(range(index, len(self))) high.unset_digit(range(0, index+1)) if int(high) != 0: high.x //= high.base self.x += int(high) return popped def digit_count(self) -> int: """ `digit_count` Similar to `bit_count`, but relitive to the current `base`. Not to be confused with `digit_length`. Returns: The amount of non-zero (non-unset) digits in the value. """ if self.x == 0: return 0 if self.base == 2: return abs(self.x).bit_count() else: c = 0 v = abs(self.x) while v != 0: if v % self.base != 0: c += 1 v //= self.base return c # gets the specified digits with their place value as an int # a higher level implementation of the concept of bit masking done with binary numbers def mask(self, index:Union[int,slice,range,Iterable[int]]) -> int: """ `mask` Similar to the concept of a 'bit mask', but on a arbitrary base. Returns a value with all digits unset except for the given index (or indexes). Arguments: index -- The index (or indexes) to mask the digits of. Returns: The value with all digits unset except for the given index (or indexes). """ if isinstance(index, int): return self._mask_value_continuous(index) slices = [] if isinstance(index, slice) and index.step == 1: slices = [index] else: if isinstance(index, slice): index = slice_to_range(index, self.digit_length()) slices = iter_to_slices(cast(Iterable[int], index), self.digit_length()) return sum(self._mask_value_continuous(s.start, s.stop - s.start) for s in slices) def digit_shift_left(self, amount:int = 1): """ `digit_shift_left` Similar to a binary shift left, shifts the value left according to the set base. Arguments: amount -- The amount to shift left. Will shift right when negative. """ if amount < 0: self.digit_shift_right(-amount) return if self.base == 2: self.x = (abs(self.x) << amount) * self.sign else: self.x *= (self.base**amount) def digit_shift_right(self, amount:int = 1): """ `digit_shift_right` Similar to a binary shift right, shifts the value right according to the set base. Arguments: amount -- The amount to shift right. Will shift left when negative. """ if amount < 0: self.digit_shift_left(-amount) return if self.base == 2: self.x = (abs(self.x) >> amount) * self.sign else: self.x //= (self.base**amount) def digit_rotate_left(self, amount:int = 1): """ `digit_rotate_left` Similar to a binary rotate left, rotates the value left according to the set base. This will pop the digit at the largest signifiant place value and inserts it at the smallest place value spot. Arguments: amount -- The amount to rotate left. Will rotate right when negative. """ if amount < 0: self.digit_rotate_right(-amount) for _ in range(amount): popped = self.pop(-1) self.digit_shift_left(1) self.x += popped def digit_rotate_right(self, amount:int = 1): """ `digit_rotate_right` Similar to a binary rotate right, rotates the value right according to the set base. This will pop the digit at the smallest signifiant place value and inserts it at the largest place value spot. Arguments: amount -- The amount to rotate right. Will rotate left when negative. """ if amount < 0: self.digit_rotate_left(-amount) for _ in range(amount): popped = self.pop(0) self.digit_shift_right(1) self.append(popped) def rstrip(self, value:Union[int,str,Iterable[Union[int,str]]]): """ `rstrip` Removes the given digit (or digits) from the right hand (units) spot. Works similarly to ``str.rstrip``, except for the fact that when ``value`` is a single string (**not** a iterable of strings) it will be treated as a single digit instead of a iterable of digits. Arguments: value -- The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit. """ if isinstance(value, Iterable): value = tuple(self._ensure_unnotated(v) for v in value) else: value = (self._ensure_unnotated(value), ) if len(value) == 0: return while self.x != 0 and self._get_single_digit(0) in value: self._pop_first() def lstrip(self, value:Union[int,str,Iterable[Union[int,str]]]): """ `rstrip` Removes the given digit (or digits) from the left hand (greatest place value) spot. Works similarly to ``str.lstrip``, except for the fact that when ``value`` is a single string (**not** a iterable of strings) it will be treated as a single digit instead of a iterable of digits. This will not strip any leading `0` digit values, as these are already not notated by default nor would effect the digit length of this intiger. Arguments: value -- The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit. """ if isinstance(value, Iterable): value = [self._ensure_unnotated(v) for v in value] else: value = [self._ensure_unnotated(value)] value.remove(0) if len(value) == 0: return while self.x != 0 and self._get_single_digit(-1) in value: self.pop(-1) def strip(self, value:Union[int,str,Iterable[Union[int,str]]]): """ `rstrip` Removes the given digit (or digits) from both sides. Works similarly to ``str.strip``, except for the fact that when ``value`` is a single string (**not** a iterable of strings) it will be treated as a single digit instead of a iterable of digits. This will not strip any leading `0` digit values, as these are already not notated by default nor would effect the digit length of this intiger. Arguments: value -- The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit. """ self.rstrip(value) self.lstrip(value) def contains(self, value:Union[int, str]) -> bool: """ `contains` Returns true if the digit value appears anywhere in this digit sequence. This will not include leading 0s, but will return true if the tested digit value is `0` and this intiger's value is also 0. Arguments: value -- The value to check for. """ value = self._ensure_unnotated(value) if self.x == 0: return value == 0 working_value = abs(self.x) while working_value > 0: if self.base == 2: if working_value & 0b1 == value: return True working_value >>= 1 else: if working_value % self.base == value: return True working_value //= self.base return False __contains__ = contains
Ancestors
- ExtendedUserInt
- UserInt
- typing.SupportsInt
- typing.SupportsFloat
- typing.SupportsAbs
- typing.SupportsComplex
- typing.SupportsRound
- typing.SupportsIndex
- typing.Protocol
- typing.Generic
- collections.abc.Hashable
- collections.abc.MutableSequence
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
Subclasses
Instance variables
prop base : int
-
base
The base of the intiger. Must be at or above 2, as this class does not support any non-standard bases.
Expand source code
@property def base(self) -> int: """ `base` The base of the intiger. Must be at or above 2, as this class does not support any non-standard bases. """ return self.__base
prop limit_high : Optional[int]
-
Inherited from:
ExtendedUserInt
.limit_high
limit_high …
prop limit_low : Optional[int]
-
Inherited from:
ExtendedUserInt
.limit_low
limit_low …
var on_changed
-
Inherited from:
ExtendedUserInt
.on_changed
on_changed
… prop radix : int
-
radix
Returns
The absolute value of the base. Will always return
base
when used in aPositionalBasedIntiger
, but may differ when using with a extended type.Expand source code
@property def radix(self) -> int: """ radix Returns: The absolute value of the base. Will always return `base` when used in a `PositionalBasedIntiger`, but may differ when using with a extended type. """ return abs(self.base)
prop sign : int
-
Inherited from:
ExtendedUserInt
.sign
sign
… prop x : int
-
Inherited from:
ExtendedUserInt
.x
x
…
Methods
def bit_count(self) ‑> int
-
Inherited from:
ExtendedUserInt
.bit_count
bit_count
… def bit_length(self) ‑> int
-
Inherited from:
ExtendedUserInt
.bit_length
bit_count
… def contains(self, value: Union[int, str]) ‑> bool
-
contains
Returns true if the digit value appears anywhere in this digit sequence. This will not include leading 0s, but will return true if the tested digit value is
0
and this intiger's value is also 0.Arguments
value – The value to check for.
def copy(self, value: Union[int, str, ForwardRef(None)] = None, base: Optional[int] = None, notation_format_override: Optional[NotationFormat] = None) ‑> PositionalBasedIntiger
-
copy
Creates a shallow copy of this object.
Keyword Arguments: value – When not
None
, will overrides thex
value of the copy. base – When notNone
, will overrides thebase
of the copy. notation_format_override – When notNone
, will overrides thedigint.notation_format
of the copy.Returns
The copy of the object.
def delete_digit(self, index: Union[int, slice, range, Iterable[int]])
-
delete_digit
Removes the value at the given index (or indexes).
Arguments
index
– The index (or indexes) digit to be removed. def digit_count(self) ‑> int
-
digit_count
Similar to
bit_count
, but relitive to the currentbase
. Not to be confused withdigit_length
.Returns
The amount of non-zero (non-unset) digits in the value.
def digit_length(self) ‑> int
-
digit_length
Similar to
bit_length
, but relitive to the currentbase
. Not to be confused withdigit_count
.Returns
The minimum necessary about of digits needed to display the number in full.
def digit_rotate_left(self, amount: int = 1)
-
digit_rotate_left
Similar to a binary rotate left, rotates the value left according to the set base. This will pop the digit at the largest signifiant place value and inserts it at the smallest place value spot.
Arguments
amount – The amount to rotate left. Will rotate right when negative.
def digit_rotate_right(self, amount: int = 1)
-
digit_rotate_right
Similar to a binary rotate right, rotates the value right according to the set base. This will pop the digit at the smallest signifiant place value and inserts it at the largest place value spot.
Arguments
amount – The amount to rotate right. Will rotate left when negative.
def digit_shift_left(self, amount: int = 1)
-
digit_shift_left
Similar to a binary shift left, shifts the value left according to the set base.
Arguments
amount – The amount to shift left. Will shift right when negative.
def digit_shift_right(self, amount: int = 1)
-
digit_shift_right
Similar to a binary shift right, shifts the value right according to the set base.
Arguments
amount – The amount to shift right. Will shift left when negative.
def fixed_sign_and(self, value: int) ‑> int
-
Inherited from:
ExtendedUserInt
.fixed_sign_and
fixed_sign_and
… def fixed_sign_invert(self) ‑> int
-
Inherited from:
ExtendedUserInt
.fixed_sign_invert
fixed_sign_invert
… def fixed_sign_or(self, value: int) ‑> int
-
Inherited from:
ExtendedUserInt
.fixed_sign_or
fixed_sign_or
… def fixed_sign_xor(self, value: int) ‑> int
-
Inherited from:
ExtendedUserInt
.fixed_sign_xor
fixed_sign_xor
… def get_digit(self, index: Union[int, slice, range, Iterable[int]]) ‑> Union[int, List[int]]
-
get_digit
Gets the specific digit's (or digits's) value at the specific index (or indexes).
Arguments
index
– The index (or indexes) in question.Returns
The value (or values, contained in a
List
) found at the index. def insert(self, index: int, value: Union[int, str, Iterable[Union[int, str]]])
-
insert
Inserts the given value (or values, following the order in which they are supplied) before the given index. When given multiple values, each value will be inserted before the given index in order.
Arguments
index
– The index (or indexes) to be inserted before.value
– The value (or values) to insert. def is_integer(self) ‑> bool
-
Inherited from:
ExtendedUserInt
.is_integer
is_integer
… def iter_digits(self, at_least: int = 0) ‑> Iterator[int]
-
iter_digits
Returns an iterable that iterates through the digit values of the integer, starting at the units spot. Will iterate 0 when all other digits are already iterated.Keyword Arguments:
at_least
– Ensures that at least the given amount of digits are iterated, if above 1.Returns
An iterator that returns the digit values, starting at the units spot.
Yields
The digits of the intiger, starting at the units spot.
def iter_symbols(self, at_least: int = 1) ‑> Iterator[str]
-
iter_symbols
Iterate the digit symbols starting at the units spot. When intending to use iteration for notation, it's suggested to use
reversed_iter_symbols
to avoid odering errors.Keyword Arguments:
at_least
– ensures that at least the given amount of symbols are returned. Defaults to 1.Returns
An iterator of symbols.
Yields
Digit symdols, starting at the units spot.
def lstrip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
rstrip
Removes the given digit (or digits) from the left hand (greatest place value) spot. Works similarly to
str.lstrip
, except for the fact that whenvalue
is a single string (not a iterable of strings) it will be treated as a single digit instead of a iterable of digits. This will not strip any leading0
digit values, as these are already not notated by default nor would effect the digit length of this intiger.Arguments
value – The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit.
def mask(self, index: Union[int, slice, range, Iterable[int]]) ‑> int
-
mask
Similar to the concept of a 'bit mask', but on a arbitrary base. Returns a value with all digits unset except for the given index (or indexes).
Arguments
index – The index (or indexes) to mask the digits of.
Returns
The value with all digits unset except for the given index (or indexes).
def notate(self, notation_format: Optional[NotationFormat] = None) ‑> str
-
notate
Notates the intiger, using the given notation format if possible, or thedigint.notation_format
set in the object's attributes if the paramater is not set.Keyword Arguments: notation_format – A notation format to use over the one set in
self.notation_format
, if notNone
.Raises
NotationError
- Raised when both the argument and attribute
digint.notation_format
areNone
; or when other errors are raised during notation.
Returns
The final notation of the intiger.
def pop(self, index: int = -1) ‑> int
-
pop
Gets the value at the given index while popping it.
Keyword Arguments: index – The target index to pop. Defaults to -1.
Returns
The value at the given index before removal.
def reversed_iter_digits(self, at_least: int = 0) ‑> Iterator[int]
-
reversed_iter_digits
Returns an iterable that iterates through the digit values of the integer, ending at the units spot. Will iterate 0 when all other digits are already iterated.Keyword Arguments:
at_least
– Ensures that at least the given amount of digits are iterated, if above 1.Returns
An iterator that returns the digit values, ending at the units spot.
Yields
The digits of the intiger, ending at the units spot.
def reversed_iter_symbols(self, at_least: int = 1) ‑> Iterator[str]
-
reversed_iter_symbols
Iterate the digit symbols ending at the units spot. Intending to be used for notation purposes, as the ordering for string notation is correct.
Keyword Arguments:
at_least
– ensures that at least the given amount of symbols are returned. Defaults to 1.Returns
An iterator of symbols.
Yields
Digit symdols, ending at the units spot.
def rstrip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
rstrip
Removes the given digit (or digits) from the right hand (units) spot. Works similarly to
str.rstrip
, except for the fact that whenvalue
is a single string (not a iterable of strings) it will be treated as a single digit instead of a iterable of digits.Arguments
value – The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit.
def set_digit(self, index: Union[int, slice, range, Iterable[int]], value: Union[int, str, Iterable[Union[int, str]]])
-
set_digit
Sets the digit (or digits) at the given index (or indexes) to the given value (or values). With multiple indexes and, there must be a matching quantity of values to set at those indexes.
Arguments
index
– The index (or indexes) to set.value
– The value (or values) to set the index (or indexes) to.Raises
ValueError
: Raised when the given value is out of bounds of the currentbase
. def strip(self, value: Union[int, str, Iterable[Union[int, str]]])
-
rstrip
Removes the given digit (or digits) from both sides. Works similarly to
str.strip
, except for the fact that whenvalue
is a single string (not a iterable of strings) it will be treated as a single digit instead of a iterable of digits. This will not strip any leading0
digit values, as these are already not notated by default nor would effect the digit length of this intiger.Arguments
value – The value (or iterable of values) to strip. Can be either a intiger digit value, or a string corelating to a single digit.
def to_bytes(self, length:
, byteorder: Literal['little', 'big'], *, signed: bool = False) ‑> bytes -
Inherited from:
ExtendedUserInt
.to_bytes
to_bytes
… def unset_digit(self, index: Union[int, slice, range, Iterable[int]])
-
unset_digit
Unsets (set to 0) the value at the given index (or indexes).
Arguments
index
– The index (or indexes) digit to be unset.