added mudolor and is even is odd

This commit is contained in:
Dominik Krenn 2025-11-05 08:11:35 +01:00
parent 7e67c3fcf9
commit 8699d8f7ab
5 changed files with 89 additions and 5 deletions

View File

@ -13,7 +13,17 @@ pip install -e .
Create digit files anywhere you like (the examples below use `instance/log`), then construct `StreamNumber` objects, and call the helpers: Create digit files anywhere you like (the examples below use `instance/log`), then construct `StreamNumber` objects, and call the helpers:
```python ```python
from mathstream import StreamNumber, add, sub, mul, div, pow from mathstream import (
StreamNumber,
add,
sub,
mul,
div,
mod,
pow,
is_even,
is_odd,
)
a = StreamNumber("instance/log/huge.txt") a = StreamNumber("instance/log/huge.txt")
b = StreamNumber("instance/log/tiny.txt") b = StreamNumber("instance/log/tiny.txt")
@ -23,7 +33,10 @@ print("sum =", "".join(add(a, b).stream()))
print("difference =", "".join(sub(a, b).stream())) print("difference =", "".join(sub(a, b).stream()))
print("product =", "".join(mul(a, b).stream())) print("product =", "".join(mul(a, b).stream()))
print("quotient =", "".join(div(a, b).stream())) print("quotient =", "".join(div(a, b).stream()))
print("modulo =", "".join(mod(a, b).stream()))
print("power =", "".join(pow(a, e).stream())) print("power =", "".join(pow(a, e).stream()))
print("a is even?", is_even(a))
print("b is odd?", is_odd(b))
``` ```
Each arithmetic call writes its result back into `instance/log` (configurable via `mathstream.number.LOG_DIR`) so you can stream the digits later or reuse them in further operations. Each arithmetic call writes its result back into `instance/log` (configurable via `mathstream.number.LOG_DIR`) so you can stream the digits later or reuse them in further operations.
@ -33,15 +46,16 @@ Each arithmetic call writes its result back into `instance/log` (configurable vi
- **StreamNumber(path)** Wraps a digit text file. The file may include an optional leading sign (`+` or `-`). Whitespace is ignored; digits must otherwise be contiguous. - **StreamNumber(path)** Wraps a digit text file. The file may include an optional leading sign (`+` or `-`). Whitespace is ignored; digits must otherwise be contiguous.
- **`.stream(chunk_size)`** Yields strings of digits with the provided chunk size. Operations in `mathstream.engine` consume these streams to avoid loading the entire number at once. - **`.stream(chunk_size)`** Yields strings of digits with the provided chunk size. Operations in `mathstream.engine` consume these streams to avoid loading the entire number at once.
- **Automatic staging** Outputs are stored under `LOG_DIR` with hashes based on input file paths, letting you compose operations without manual bookkeeping. - **Automatic staging** Outputs are stored under `LOG_DIR` with hashes based on input file paths, letting you compose operations without manual bookkeeping.
- **Sign-aware** Addition, subtraction, multiplication, division (`//` behavior), and exponentiation (non-negative exponents) all respect operand sign. Division follows Pythons floor division rules. - **Sign-aware** Addition, subtraction, multiplication, division (`//` behavior), modulo, and exponentiation (non-negative exponents) all respect operand sign. Division/modulo follow Pythons floor-division rules.
- **Utilities** `clear_logs()` wipes prior staged results so you can start fresh. - **Utilities** `clear_logs()` wipes prior staged results so you can start fresh.
- **Parity helpers** `is_even` and `is_odd` inspect the streamed digits without materializing the integer.
## Example Script ## Example Script
`test.py` in the repository root demonstrates a minimal workflow: `test.py` in the repository root demonstrates a minimal workflow:
1. Writes sample operands to `tests/*.txt`. 1. Writes sample operands to `tests/*.txt`.
2. Calls every arithmetic primitive. 2. Calls every arithmetic primitive plus the modulo/parity helpers.
3. Asserts that the streamed outputs match known values (helpful for quick regression checks). 3. Asserts that the streamed outputs match known values (helpful for quick regression checks).
Run it via: Run it via:

View File

@ -1,2 +1,11 @@
from .engine import clear_logs, add, sub, mul, div, pow from .engine import clear_logs, add, sub, mul, div, mod, pow, is_even, is_odd
from .number import StreamNumber from .number import StreamNumber
__all__ = [
"clear_logs",
"add", "sub",
"mul", "div", "mod",
"pow",
"is_even", "is_odd",
"StreamNumber",
]

View File

@ -261,6 +261,26 @@ def div(num_a: StreamNumber, num_b: StreamNumber) -> StreamNumber:
return _write_result("div", (num_a, num_b), result) return _write_result("div", (num_a, num_b), result)
def mod(num_a: StreamNumber, num_b: StreamNumber) -> StreamNumber:
"""Return num_a % num_b following Python's floor-division semantics."""
sign_a, a_digits = _normalize_stream(num_a)
sign_b, b_digits = _normalize_stream(num_b)
_, remainder = _divide_abs(a_digits, b_digits)
if remainder == "0":
return _write_result("mod", (num_a, num_b), "0")
if sign_a == sign_b:
digits = remainder
else:
digits = _sub_abs(b_digits, remainder)
sign = 1 if sign_b > 0 else -1
result = digits if sign > 0 else f"-{digits}"
return _write_result("mod", (num_a, num_b), result)
def pow(num_a: StreamNumber, num_b: StreamNumber) -> StreamNumber: def pow(num_a: StreamNumber, num_b: StreamNumber) -> StreamNumber:
"""Return num_a ** num_b using repeated squaring (integer exponent only).""" """Return num_a ** num_b using repeated squaring (integer exponent only)."""
base_sign, base_digits = _normalize_stream(num_a) base_sign, base_digits = _normalize_stream(num_a)
@ -289,3 +309,14 @@ def pow(num_a: StreamNumber, num_b: StreamNumber) -> StreamNumber:
result_sign = 1 result_sign = 1
result = result_digits if result_sign > 0 else f"-{result_digits}" result = result_digits if result_sign > 0 else f"-{result_digits}"
return _write_result("pow", (num_a, num_b), result) return _write_result("pow", (num_a, num_b), result)
def is_even(num: StreamNumber) -> bool:
"""Return True if the streamed integer is even."""
_, digits = _normalize_stream(num)
return (ord(digits[-1]) - 48) % 2 == 0
def is_odd(num: StreamNumber) -> bool:
"""Return True if the streamed integer is odd."""
return not is_even(num)

31
test.py
View File

@ -2,7 +2,18 @@ from __future__ import annotations
from pathlib import Path from pathlib import Path
from mathstream import StreamNumber, add, sub, mul, div, pow, clear_logs from mathstream import (
StreamNumber,
add,
sub,
mul,
div,
mod,
pow,
is_even,
is_odd,
clear_logs,
)
NUMBERS_DIR = Path(__file__).parent / "tests" NUMBERS_DIR = Path(__file__).parent / "tests"
@ -27,6 +38,11 @@ def check(label: str, result: StreamNumber, expected: str) -> None:
print(f"{label} = {actual}") print(f"{label} = {actual}")
def check_bool(label: str, value: bool, expected: bool) -> None:
assert value is expected, f"{label} expected {expected}, got {value}"
print(f"{label} = {value}")
def main() -> None: def main() -> None:
clear_logs() clear_logs()
@ -35,6 +51,7 @@ def main() -> None:
small = write_number("tiny", "34567") small = write_number("tiny", "34567")
negative = write_number("negative", "-1200") negative = write_number("negative", "-1200")
exponent = write_number("power", "5") exponent = write_number("power", "5")
negative_divisor = write_number("neg_divisor", "-34567")
# Showcase the core operations. # Showcase the core operations.
total = add(big, small) total = add(big, small)
@ -42,6 +59,10 @@ def main() -> None:
product = mul(small, negative) product = mul(small, negative)
quotient = div(big, small) quotient = div(big, small)
powered = pow(small, exponent) powered = pow(small, exponent)
modulus = mod(big, small)
neg_mod_pos = mod(negative, small)
pos_mod_neg = mod(small, negative)
neg_mod_neg = mod(negative, negative_divisor)
print("Operands stored under:", NUMBERS_DIR) print("Operands stored under:", NUMBERS_DIR)
check("huge + tiny", total, "98765432123491356") check("huge + tiny", total, "98765432123491356")
@ -49,6 +70,14 @@ def main() -> None:
check("tiny * negative", product, "-41480400") check("tiny * negative", product, "-41480400")
check("huge // tiny", quotient, "2857217349595") check("huge // tiny", quotient, "2857217349595")
check("tiny ** power", powered, "49352419431622775997607") check("tiny ** power", powered, "49352419431622775997607")
check("huge % tiny", modulus, "6424")
check("negative % tiny", neg_mod_pos, "33367")
check("tiny % negative", pos_mod_neg, "-233")
check("negative % neg_divisor", neg_mod_neg, "-1200")
check_bool("is_even(negative)", is_even(negative), True)
check_bool("is_even(tiny)", is_even(small), False)
check_bool("is_odd(tiny)", is_odd(small), True)
check_bool("is_odd(negative)", is_odd(negative), False)
if __name__ == "__main__": if __name__ == "__main__":

1
tests/neg_divisor.txt Normal file
View File

@ -0,0 +1 @@
-34567