Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Refine extend_precision by using biguint methods
  • Loading branch information
forfudan committed Jul 17, 2025
commit d5cde3418e354cee82e050deedece0ffc95d4264
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ tempCodeRunnerFile.mojo
*.log
# local files
/test*.mojo
/test*.py
local
98 changes: 56 additions & 42 deletions src/decimojo/bigdecimal/bigdecimal.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -903,72 +903,86 @@ struct BigDecimal(
"""
return self.coefficient.number_of_digits() - 1 - self.scale

fn extend_precision(self, precision_diff: Int) raises -> BigDecimal:
fn extend_precision(self, precision_diff: Int) -> BigDecimal:
"""Returns a number with additional decimal places (trailing zeros).
This multiplies the coefficient by 10^precision_diff and increases
the scale accordingly, preserving the numeric value.
If `precision_diff` is negative, nothing is done and the
original number is returned.

Args:
precision_diff: The number of decimal places to add.
precision_diff: The number of decimal places to add, which must be
non-negative.

Returns:
A new BigDecimal with increased precision.

Raises:
Error: If `precision_diff` is negative.
Notes:

In debug mode, negative `precision_diff` raises an assertion error.

Examples:
```
print(BigDecimal("123.456).scale_up(5)) # Output: 123.45600000
print(BigDecimal("123456").scale_up(3)) # Output: 123456.000
print(BigDecimal("123456").scale_up(-1)) # Error!
print(BigDecimal("123456").scale_up(-1)) # Output: 123456 (no change)
```
End of examples.
"""
if precision_diff < 0:
raise Error(
"`extend_precision()`: "
"Cannot extend precision with negative value"
)
debug_assert(
precision_diff >= 0,
"bigdecimal.BigDecimal.extend_precision(): ",
"precision_diff must be non-negative, got: ",
precision_diff,
)

if precision_diff == 0:
if precision_diff <= 0:
return self

var number_of_words_to_add = precision_diff // 9
var number_of_remaining_digits_to_add = precision_diff % 9

var coefficient = self.coefficient

if number_of_remaining_digits_to_add == 0:
pass
elif number_of_remaining_digits_to_add == 1:
coefficient = coefficient * BigUInt(UInt32(10))
elif number_of_remaining_digits_to_add == 2:
coefficient = coefficient * BigUInt(UInt32(100))
elif number_of_remaining_digits_to_add == 3:
coefficient = coefficient * BigUInt(UInt32(1_000))
elif number_of_remaining_digits_to_add == 4:
coefficient = coefficient * BigUInt(UInt32(10_000))
elif number_of_remaining_digits_to_add == 5:
coefficient = coefficient * BigUInt(UInt32(100_000))
elif number_of_remaining_digits_to_add == 6:
coefficient = coefficient * BigUInt(UInt32(1_000_000))
elif number_of_remaining_digits_to_add == 7:
coefficient = coefficient * BigUInt(UInt32(10_000_000))
else: # number_of_remaining_digits_to_add == 8
coefficient = coefficient * BigUInt(UInt32(100_000_000))

var words: List[UInt32] = List[UInt32]()
for _ in range(number_of_words_to_add):
words.append(UInt32(0))
words.extend(coefficient.words)

return BigDecimal(
BigUInt(words^),
decimojo.biguint.arithmetics.multiply_by_power_of_ten(
self.coefficient, precision_diff
),
self.scale + precision_diff,
self.sign,
)

fn extend_precision_inplace(mut self, precision_diff: Int):
"""Add additional decimal places (trailing zeros) in-place.
This multiplies the coefficient by 10^precision_diff and increases
the scale accordingly, preserving the numeric value.
If `precision_diff` is negative, nothing is done and the
original number is returned.

Args:
precision_diff: The number of decimal places to add, which must be
non-negative.

Notes:

In debug mode, negative `precision_diff` raises an assertion error.

Examples:
```
print(BigDecimal("123.456).scale_up(5)) # Output: 123.45600000
print(BigDecimal("123456").scale_up(3)) # Output: 123456.000
print(BigDecimal("123456").scale_up(-1)) # Output: 123456 (no change)
```
"""
debug_assert(
precision_diff >= 0,
"bigdecimal.BigDecimal.extend_precision(): ",
"precision_diff must be non-negative, got: ",
precision_diff,
)

if precision_diff <= 0:
return

decimojo.biguint.arithmetics.multiply_inplace_by_power_of_ten(
self.coefficient, precision_diff
)
self.scale += precision_diff

@always_inline
fn print_internal_representation(self):
"""Prints the internal representation of the BigDecimal."""
Expand Down
10 changes: 7 additions & 3 deletions src/decimojo/str.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
# limitations under the License.
# ===----------------------------------------------------------------------=== #

"""String manipulation functions."""

import time
"""String parsing and manipulation functions."""


fn parse_numeric_string(
Expand Down Expand Up @@ -93,13 +91,16 @@ fn parse_numeric_string(

for code_ptr in value_bytes:
ref code = code_ptr

# If the char is " ", skip it
if code == 32:
pass

# If the char is "," or "_", skip it
elif code == 44 or code == 95:
unexpected_end_char = True
# If the char is "-"

elif code == 45:
unexpected_end_char = True
if exponent_sign_read:
Expand All @@ -112,6 +113,7 @@ fn parse_numeric_string(
else:
mantissa_sign = True
mantissa_sign_read = True

# If the char is "+"
elif code == 43:
unexpected_end_char = True
Expand All @@ -124,6 +126,7 @@ fn parse_numeric_string(
else:
mantissa_sign_read = True
# If the char is "."

elif code == 46:
unexpected_end_char = False
if decimal_point_read:
Expand All @@ -132,6 +135,7 @@ fn parse_numeric_string(
decimal_point_read = True
mantissa_sign_read = True
# If the char is "e" or "E"

elif code == 101 or code == 69:
unexpected_end_char = True
if exponent_notation_read:
Expand Down