diff --git a/README.md b/README.md index 73cd27c..a29a73e 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,12 @@ Rome is not built in one day. DeciMojo is currently under active development. Co ## Examples -Here presents 10 key examples of how to use the `Decimal` type with the most common operations. +Here are 10 key examples of how to use the `Decimal` type with the most important features. ### 1. Creating Decimals ```mojo -from decimojo import Decimal +from decimojo.prelude import * # From string with various formats var d1 = Decimal("123.45") # Regular decimal @@ -36,11 +36,11 @@ var d4 = Decimal("1_000_000.00") # Readable format with underscores # From integers and floats var d5 = Decimal(123) # Integer var d6 = Decimal(123.45) # Float (approximate) -var d7 = Decimal(123.45, max_precision=True) # Float with maximum precision -# From components -var d8 = Decimal(12345, 0, 0, False, 2) # 123.45 (coefficient 12345, scale 2) -var d9 = Decimal(12345, 0, 0, True, 2) # -123.45 (negative flag set) +# Special values +var max_val = Decimal.MAX() # 79228162514264337593543950335 +var min_val = Decimal.MIN() # -79228162514264337593543950335 +var zero = Decimal.ZERO() # 0 ``` ### 2. Basic Arithmetic Operations @@ -61,165 +61,156 @@ var quot = Decimal("123.45") / Decimal("2.5") # 49.38 # Negation var neg = -Decimal("123.45") # -123.45 -# Power (exponentiation) -var squared = Decimal("2.5") ** 2 # 6.25 -var cubed = Decimal("2") ** 3 # 8 -var reciprocal = Decimal("2") ** (-1) # 0.5 +# Absolute value +var abs_val = abs(Decimal("-123.45")) # 123.45 ``` -### 3. Rounding with Different Modes +### 3. Exponentiation (Power Functions) ```mojo -from decimojo import Decimal -from decimojo.rounding_mode import RoundingMode -from decimojo.mathematics import round - -var num = Decimal("123.456789") - -# Round to various decimal places with different modes -var default_round = round(num, 2) # 123.46 (HALF_EVEN) -var down = round(num, 2, RoundingMode.DOWN()) # 123.45 (truncate) -var up = round(num, 2, RoundingMode.UP()) # 123.46 (away from zero) -var half_up = round(num, 2, RoundingMode.HALF_UP()) # 123.46 (≥0.5 rounds up) - -# Rounding special cases -var half_value = round(Decimal("123.5"), 0) # 124 (banker's rounding) -var half_odd = round(Decimal("124.5"), 0) # 124 (banker's rounding to even) +# Integer exponents +var squared = Decimal("2.5") ** 2 # 6.25 +var cubed = Decimal("2") ** 3 # 8 +var tenth_power = Decimal("2") ** 10 # 1024 + +# Negative exponents +var reciprocal = Decimal("2") ** (-1) # 0.5 +var inverse_square = Decimal("2") ** (-2) # 0.25 + +# Special cases +var anything_power_zero = Decimal("123.45") ** 0 # 1 +var one_power_anything = Decimal("1") ** 100 # 1 +var zero_power_positive = Decimal("0") ** 5 # 0 ``` -### 4. Working with Scale and Precision +### 4. Type Conversions ```mojo -var d = Decimal("123.45") # Scale is 2 -print(d.scale()) # Prints: 2 +var d = Decimal("123.456") -# Changing scale through rounding -var more_precise = round(d, 4) # 123.4500 -print(more_precise.scale()) # Prints: 4 +# String conversion +var str_val = String(d) # "123.456" -var less_precise = round(d, 1) # 123.5 (rounds up) -print(less_precise.scale()) # Prints: 1 +# Integer conversion (truncates toward zero) +var int_val = Int(d) # 123 -# Scale after operations -var a = Decimal("123.45") # Scale 2 -var b = Decimal("67.890") # Scale 3 -print((a + b).scale()) # Prints: 3 (takes the larger scale) -print((a * b).scale()) # Scale becomes 5 (sum of scales) +# Float conversion +var float_val = Float64(d) # 123.456 + +# Check if value can be represented as an integer +var is_int = d.is_integer() # False +var whole_num = Decimal("100.000") +var is_whole = whole_num.is_integer() # True ``` -### 5. Zero and Special Values +### 5. Working with Scale and Precision ```mojo -# Different ways to represent zero -var z1 = Decimal("0") # 0 -var z2 = Decimal("0.00") # 0.00 -print(z1.is_zero(), z2.is_zero()) # Both print: True +var d = Decimal("123.45") +var scale_val = d.scale() # 2 (number of decimal places) -# Special values from static methods -var max_val = Decimal.MAX() # 79228162514264337593543950335 -var min_val = Decimal.MIN() # -79228162514264337593543950335 -var one = Decimal.ONE() # 1 -var neg_one = Decimal.NEGATIVE_ONE() # -1 -var zero = Decimal.ZERO() # 0 +# Operations respect and combine scales appropriately +var a = Decimal("123.45") # Scale 2 +var b = Decimal("67.890") # Scale 3 +var addition = a + b # Scale 3 (the larger scale) +var multiplication = a * b # Scale 5 (sum of scales) + +# Very high precision values are supported +var high_precision = Decimal("0.123456789012345678901234567") # 27 decimal places ``` -### 6. Handling Very Small and Large Numbers +### 6. Edge Cases Handling ```mojo -# Very small number (1 at 28th decimal place - maximum precision) -var small = Decimal("0." + "0" * 27 + "1") -print(small) # 0.0000000000000000000000000001 - -# Large number close to max -var large = Decimal("79228162514264337593543950334") # MAX() - 1 -print(large) # 79228162514264337593543950334 +# Division by zero is detected +try: + var undefined = Decimal("1") / Decimal("0") + print("This won't print") +except: + print("Division by zero detected") -# Calculations with extreme values -var small_squared = small ** 2 # Even smaller number +# Overflow is detected +try: + var max_val = Decimal.MAX() + var overflow = max_val + Decimal("1") + print("This won't print") +except: + print("Overflow detected") -# Division resulting in long repeating decimal -var repeating = Decimal("1") / Decimal("3") # 0.333333... (up to max precision) -print(repeating) # 0.3333333333333333333333333333 +# Zero handling +var zero = Decimal("0") +var is_zero = zero.is_zero() # True +var zero_with_scale = Decimal("0.00000") +var also_zero = zero_with_scale.is_zero() # True ``` -### 7. Type Conversions +### 7. Working with Very Small and Large Numbers ```mojo -var d = Decimal("123.456") +# Very small number (maximum precision) +var small = Decimal("0." + "0" * 27 + "1") # 0.0000000000000000000000000001 -# String representation -var str_val = String(d) # "123.456" - -# Integer conversion (throws error if has fractional part) -try: - var int_val = Int(d) # Error: has non-zero fractional part - print("This won't print") -except: - print("Cannot convert to Int with non-zero fraction") +# Very large number +var large = Decimal("79228162514264337593543950334") # Near maximum value -# Integer conversion for whole number with decimal places -var whole = Decimal("100.000") -var int_whole = Int(whole) # 100 (works because fractional part is zero) +# Operations with extreme values +var very_small_sum = small + small # 0.0000000000000000000000000002 +var small_product = small * small # Might result in underflow to zero due to precision limits ``` -### 8. Working with Integer Checking +### 8. Negative Numbers ```mojo -# Check if a Decimal represents an integer (even if it has decimal places) -var d1 = Decimal("123") # Scale 0 -var d2 = Decimal("123.0") # Scale 1 -var d3 = Decimal("123.456") # Scale 3 - -print(d1.is_integer()) # True -print(d2.is_integer()) # True - all fractional digits are 0 -print(d3.is_integer()) # False - has non-zero fractional digits +# Creating negative numbers +var neg1 = Decimal("-123.45") +var neg2 = -Decimal("123.45") # Same as above + +# Sign operations +var is_negative = neg1.is_negative() # True +var abs_value = abs(neg1) # 123.45 +var negate_again = -neg1 # 123.45 + +# Arithmetic with mixed signs +var prod_neg_pos = neg1 * Decimal("2") # -246.90 +var prod_neg_neg = neg1 * neg2 # 15240.0025 (positive result) ``` -### 9. Error Handling +### 9. Equality and Comparison ```mojo -# Handle division by zero -try: - var result = Decimal("123.45") / Decimal("0") - print("This won't print") -except: - print("Correctly caught division by zero") +var a = Decimal("123.45") +var b = Decimal("123.450") # Same value but different scale -# Handle overflow -try: - var max_value = Decimal.MAX() - var overflow_attempt = max_value + Decimal("1") - print("This won't print") -except: - print("Correctly caught overflow") +# Equality checks the numeric value, not the representation +var equal = (a == b) # True -# Handle invalid power operation -try: - var zero_neg_power = Decimal("0") ** (-1) - print("This won't print") -except: - print("Correctly caught zero raised to negative power") +# Self-comparisons +var self_equal = (a == a) # Always True + +# Zero comparisons with different scales +var zero1 = Decimal("0") +var zero2 = Decimal("0.000") +var zeros_equal = (zero1 == zero2) # True ``` -### 10. Mathematics Module +### 10. Mathematics Functions ```mojo -from decimojo import Decimal -from decimojo.mathematics import power +from decimojo.mathematics import sqrt -# Two equivalent ways to compute powers -var result1 = Decimal("2.5") ** 2 -var result2 = power(Decimal("2.5"), 2) +# Square root +var root = sqrt(Decimal("16")) # 4 -print(String(result1) == String(result2)) # True +# Rounding to specific decimal places +var rounded = round(Decimal("123.456"), 2) # 123.46 -# More complex power operations -var cube = power(Decimal("2"), 3) # 8 -var reciprocal = power(Decimal("2"), -1) # 0.5 +# Absolute value (two equivalent ways) +var abs1 = abs(Decimal("-123.45")) # 123.45 +var abs2 = abs(Decimal("-123.45")) # 123.45 -# Can also pass a Decimal exponent (must be an integer value) -var exp_as_decimal = Decimal("3") -var cubed = power(Decimal("2"), exp_as_decimal) # 8 +# Calculating with arbitrary precision +var precise_div = Decimal("1") / Decimal("7") # 0.1428571428571428571428571429 +var precise_sqrt = sqrt(Decimal("2")) # 1.414213562373095048801688724 ``` ## Related Projects diff --git a/decimojo/decimal.mojo b/decimojo/decimal.mojo index daf608b..18b2793 100644 --- a/decimojo/decimal.mojo +++ b/decimojo/decimal.mojo @@ -25,7 +25,14 @@ Implements basic object methods for working with decimal numbers. from .rounding_mode import RoundingMode -struct Decimal(Roundable, Writable): +struct Decimal( + Absable, + Comparable, + Floatable, + Intable, + Roundable, + Writable, +): """ Correctly-rounded fixed-precision number. @@ -566,15 +573,33 @@ struct Decimal(Roundable, Writable): # Output dunders, type-transfer dunders, and other methods # ===------------------------------------------------------------------=== # - fn __int__(self) raises -> Int: + fn __float__(self) -> Float64: + """ + Converts this Decimal to a floating-point value. + Because Decimal is fixed-point, this may lose precision. + + Returns: + The floating-point representation of this Decimal. + """ + var coefficient = self.coefficient() + var result = Float64(0) + + for i in range(len(coefficient)): + var digit = ord(coefficient[i]) - ord("0") + result = result * 10 + digit + + result = result / (10 ** self.scale()) + + result = -result if self.is_negative() else result + + return result + + fn __int__(self) -> Int: """ Converts this Decimal to an Int value. Returns: The Int representation of this Decimal. - - Raises: - Error: If the Decimal has a non-zero fractional part. """ var scale = self.scale() @@ -595,14 +620,6 @@ struct Decimal(Roundable, Writable): # Value is less than 1, so integer part is 0 return 0 - # Check if all fractional digits are 0 - for i in range(len(coef) - scale, len(coef)): - if coef[i] != "0": - raise Error( - "Cannot convert Decimal with non-zero fractional part" - " to Int" - ) - # Get the integer part var int_part = coef[: len(coef) - scale] var result: Int = 0 @@ -668,6 +685,18 @@ struct Decimal(Roundable, Writable): # neg # ===------------------------------------------------------------------=== # + fn __abs__(self) -> Self: + """ + Returns the absolute value of this Decimal. + + Returns: + The absolute value of this Decimal. + """ + var result = Decimal(self.low, self.mid, self.high, self.flags) + result.flags &= ~Self.SIGN_MASK # Clear sign bit + + return result + fn __neg__(self) -> Self: """Unary negation operator.""" var result = Decimal(self.low, self.mid, self.high, self.flags) @@ -1432,7 +1461,7 @@ struct Decimal(Roundable, Writable): var temp = result # Collect the digits to be removed (we need all of them for proper rounding) - for i in range(scale_diff): + for _ in range(scale_diff): # Divide by 10 without any rounding at this stage var high64 = UInt64(temp.high) var mid64 = UInt64(temp.mid) @@ -1551,7 +1580,7 @@ struct Decimal(Roundable, Writable): ) # Scale up by multiplying by powers of 10 - for i in range(scale_diff): + for _ in range(scale_diff): # Check for potential overflow before multiplying if result.high > 0xFFFFFFFF // 10 or ( result.high == 0xFFFFFFFF // 10 and result.low > 0xFFFFFFFF % 10 diff --git a/decimojo/prelude.mojo b/decimojo/prelude.mojo new file mode 100644 index 0000000..abff666 --- /dev/null +++ b/decimojo/prelude.mojo @@ -0,0 +1,19 @@ +""" +prelude +======= + +tries to find out a balance by providing a list of things +that can be imported at one time. +The list contains the functions or types +that are the most essential for a user. + +You can use the following code to import them: + +```mojo +from decimojo.prelude import * +``` +""" + +import decimojo as dm +from decimojo import Decimal +from decimojo import RoundingMode diff --git a/decimojo/rounding_mode.mojo b/decimojo/rounding_mode.mojo index 0fbe91c..9fe27bd 100644 --- a/decimojo/rounding_mode.mojo +++ b/decimojo/rounding_mode.mojo @@ -16,6 +16,12 @@ struct RoundingMode: - UP: Round away from zero """ + # alias + alias down = Self.DOWN() + alias half_up = Self.HALF_UP() + alias half_even = Self.HALF_EVEN() + alias up = Self.UP() + # Internal value var value: Int diff --git a/examples/examples.mojo b/examples/examples.mojo deleted file mode 100644 index 9244c8d..0000000 --- a/examples/examples.mojo +++ /dev/null @@ -1,348 +0,0 @@ -""" -Examples demonstrating the usage of Decimojo's Decimal type. -""" -from decimojo import Decimal, round -from decimojo.rounding_mode import RoundingMode - - -fn print_section(title: String): - """Helper function to print section headers.""" - print("\n" + "=" * 50) - print(title) - print("=" * 50) - - -fn creating_decimal_values() raises: - print_section("CREATING DECIMAL VALUES") - - print("\nFrom String:") - # Basic decimal values - var d1 = Decimal("123.45") - var d2 = Decimal("-67.89") - var d3 = Decimal("0.0001234") - var d4 = Decimal("1234567890") - var d5 = Decimal("0") - - print("d1 (123.45):", d1) - print("d2 (-67.89):", d2) - print("d3 (0.0001234):", d3) - print("d4 (1234567890):", d4) - print("d5 (0):", d5) - - # Scientific notation - var s1 = Decimal("1.23e5") - var s2 = Decimal("4.56e-3") - print("\nScientific notation:") - print("s1 (1.23e5):", s1) - print("s2 (4.56e-3):", s2) - - # String formatting variations - var f1 = Decimal("1_000_000.00") - var f2 = Decimal(" 123.45 ") - print("\nFormatting variations:") - print("f1 (1_000_000.00):", f1) - print("f2 (' 123.45 '):", f2) - - print("\nFrom Integer:") - var i1 = Decimal(123) - var i2 = Decimal(-456) - var i3 = Decimal(0) - print("i1 (123):", i1) - print("i2 (-456):", i2) - print("i3 (0):", i3) - - print("\nFrom Float:") - var float1 = Decimal(123.45) - var float2 = Decimal(-67.89) - var float3 = Decimal(0.0001234) - print("float1 (123.45):", float1) - print("float2 (-67.89):", float2) - print("float3 (0.0001234):", float3) - - print("\nWith max_precision parameter:") - var p1 = Decimal(123.45, max_precision=True) - var p2 = Decimal(123.45, max_precision=False) - print("p1 (max_precision=True):", p1) - print("p2 (max_precision=False):", p2) - - print("\nUsing Static Constants:") - var zero = Decimal.ZERO() - var one = Decimal.ONE() - var neg_one = Decimal.NEGATIVE_ONE() - var max_val = Decimal.MAX() - var min_val = Decimal.MIN() - print("ZERO():", zero) - print("ONE():", one) - print("NEGATIVE_ONE():", neg_one) - print("MAX():", max_val) - print("MIN():", min_val) - - -fn arithmetic_operations() raises: - print_section("ARITHMETIC OPERATIONS") - - print("\nAddition:") - var a = Decimal("123.45") - var b = Decimal("67.89") - var result = a + b - print("123.45 + 67.89 =", result) - - # Adding with different scales - var c = Decimal("123.4") - var d = Decimal("67.89") - var result2 = c + d - print("123.4 + 67.89 =", result2) - - # Adding with negative numbers - var e = Decimal("123.45") - var f = Decimal("-67.89") - var result3 = e + f - print("123.45 + (-67.89) =", result3) - - # Adding zero - var g = Decimal("123.45") - var h = Decimal("0") - var result4 = g + h - print("123.45 + 0 =", result4) - - print("\nSubtraction:") - var a_sub = Decimal("123.45") - var b_sub = Decimal("67.89") - var result_sub = a_sub - b_sub - print("123.45 - 67.89 =", result_sub) - - # Subtraction resulting in negative - var c_sub = Decimal("67.89") - var d_sub = Decimal("123.45") - var result_sub2 = c_sub - d_sub - print("67.89 - 123.45 =", result_sub2) - - # Subtracting with different scales - var e_sub = Decimal("123.4") - var f_sub = Decimal("67.89") - var result_sub3 = e_sub - f_sub - print("123.4 - 67.89 =", result_sub3) - - # Subtracting to zero - var g_sub = Decimal("123.45") - var h_sub = Decimal("123.45") - var result_sub4 = g_sub - h_sub - print("123.45 - 123.45 =", result_sub4) - - print("\nMultiplication:") - var a_mul = Decimal("12.34") - var b_mul = Decimal("5.67") - var result_mul = a_mul * b_mul - print("12.34 * 5.67 =", result_mul) - - # Multiplying with negative numbers - var c_mul = Decimal("12.34") - var d_mul = Decimal("-5.67") - var result_mul2 = c_mul * d_mul - print("12.34 * (-5.67) =", result_mul2) - - # Multiplying by zero - var e_mul = Decimal("12.34") - var f_mul = Decimal("0") - var result_mul3 = e_mul * f_mul - print("12.34 * 0 =", result_mul3) - - # Multiplying by one - var g_mul = Decimal("12.34") - var h_mul = Decimal("1") - var result_mul4 = g_mul * h_mul - print("12.34 * 1 =", result_mul4) - - # Multiplying large numbers - var i_mul = Decimal("1234567.89") - var j_mul = Decimal("9876543.21") - var result_mul5 = i_mul * j_mul - print("1234567.89 * 9876543.21 =", result_mul5) - - print("\nNegation:") - var a_neg = Decimal("123.45") - var result_neg = -a_neg - print("-123.45 =", result_neg) - - var b_neg = Decimal("-67.89") - var result_neg2 = -b_neg - print("-(-67.89) =", result_neg2) - - var c_neg = Decimal("0") - var result_neg3 = -c_neg - print("-0 =", result_neg3) - - -fn rounding_and_precision() raises: - print_section("ROUNDING AND PRECISION") - - print("\nRounding to Specific Decimal Places:") - var d = Decimal("123.456789") - print("Original value:", d) - - # Default rounding (HALF_EVEN/banker's rounding) - var r1 = round(d, 2) - var r2 = round(d, 4) - var r3 = round(d, 0) - print("Rounded to 2 places (default):", r1) - print("Rounded to 4 places (default):", r2) - print("Rounded to 0 places (default):", r3) - - # Using different rounding modes - var down = round(d, 2, RoundingMode.DOWN()) - var up = round(d, 2, RoundingMode.UP()) - var half_up = round(d, 2, RoundingMode.HALF_UP()) - var half_even = round(d, 2, RoundingMode.HALF_EVEN()) - print("\nRounding 123.456789 to 2 places with different modes:") - print("DOWN():", down) - print("UP():", up) - print("HALF_UP():", half_up) - print("HALF_EVEN():", half_even) - - # Rounding special cases - var half_val = Decimal("123.5") - var half_rounded = round(half_val, 0, RoundingMode.HALF_EVEN()) - var val = Decimal("124.5") - var even_rounded = round(val, 0, RoundingMode.HALF_EVEN()) - print("\nRounding special cases (banker's rounding):") - print("123.5 rounded to 0 places:", half_rounded) - print("124.5 rounded to 0 places:", even_rounded) - - print("\nWorking with Scale:") - var d_scale = Decimal("123.45") - print("Value:", d_scale, "- Scale:", d_scale.scale()) - - # Round to different scales - var rounded = round(d_scale, 3) - print("Rounded to 3 places:", rounded, "- New scale:", rounded.scale()) - - # Scale after arithmetic operations - var a_scale = Decimal("123.45") # scale 2 - var b_scale = Decimal("67.890") # scale 3 - var sum_scale = a_scale + b_scale - print("\nAddition with different scales:") - print( - a_scale, - "(scale", - a_scale.scale(), - ") +", - b_scale, - "(scale", - b_scale.scale(), - ") =", - ) - print(sum_scale, "(scale", sum_scale.scale(), ")") - - -fn string_conversion_and_printing() raises: - print_section("STRING CONVERSION AND PRINTING") - - var d = Decimal("123.45") - print("Decimal value:", d) - - # Convert to string using String() - var str_val = String(d) - print("As string:", str_val) - - # Preserving trailing zeros - var d2 = Decimal("123.4500") - print("With trailing zeros:", d2) - - # Printing very small numbers - var small = Decimal("0.0000001234") - print("Very small number:", small) - - # Printing integer values - var int_val = Decimal("1000") - print("Integer value:", int_val) - - -fn display_decimal_details(d: Decimal): - """Function to display internal representation.""" - print("Value: ", d) - print("Coefficient: ", d.coefficient()) - print("Scale: ", d.scale()) - print("Is negative: ", d.is_negative()) - print("Is zero: ", d.is_zero()) - print("Internal fields:") - print(" - low: ", d.low) - print(" - mid: ", d.mid) - print(" - high: ", d.high) - print(" - flags: ", d.flags) - print("-------------------------") - - -fn examining_internal_representation() raises: - print_section("EXAMINING INTERNAL REPRESENTATION") - - var d1 = Decimal("123.45") - print("Regular decimal (123.45):") - display_decimal_details(d1) - - var d2 = Decimal("-0.0001") - print("\nSmall negative decimal (-0.0001):") - display_decimal_details(d2) - - var d3 = Decimal("79228162514264337593543950335") # MAX - print("\nMaximum value:") - display_decimal_details(d3) - - -fn working_with_edge_cases() raises: - print_section("WORKING WITH EDGE CASES") - - # Maximum value - var max_value = Decimal.MAX() - print("Maximum value:", max_value) - - # Minimum value - var min_value = Decimal.MIN() - print("Minimum value:", min_value) - - # Very small numbers - var small = Decimal("0." + "0" * 27 + "1") # 1 at 28th decimal place - print("Very small number (1 at 28th decimal place):", small) - - # Very precise numbers - var precise = Decimal("0." + "1" * 28) # 28 decimal places - print("Very precise number (28 decimal places of 1s):", precise) - - print("\nZero Values with Different Scales:") - var z1 = Decimal("0") - var z2 = Decimal("0.0") - var z3 = Decimal("0.00") - var z4 = Decimal("0.000000") - - print("z1 (scale", z1.scale(), "):", z1) - print("z2 (scale", z2.scale(), "):", z2) - print("z3 (scale", z3.scale(), "):", z3) - print("z4 (scale", z4.scale(), "):", z4) - - print("\nAre they all zero?") - print("z1.is_zero():", z1.is_zero()) - print("z2.is_zero():", z2.is_zero()) - print("z3.is_zero():", z3.is_zero()) - print("z4.is_zero():", z4.is_zero()) - - print("\nMaximum Precision Handling:") - var max_prec = Decimal("0.1234567890123456789012345678") - print("Max precision (28 places):", max_prec) - - var too_precise = Decimal("0.12345678901234567890123456789") - print("Beyond max precision (29 places, will be rounded):", too_precise) - - -fn main() raises: - print("DECIMOJO EXAMPLES") - print("=================\n") - - creating_decimal_values() - arithmetic_operations() - rounding_and_precision() - string_conversion_and_printing() - examining_internal_representation() - working_with_edge_cases() - - print("\n" + "=" * 50) - print("END OF EXAMPLES") - print("=" * 50) diff --git a/mojoproject.toml b/mojoproject.toml index 8ac81c9..192f72d 100644 --- a/mojoproject.toml +++ b/mojoproject.toml @@ -1,6 +1,6 @@ [project] authors = ["ZHU Yuhao 朱宇浩 "] -channels = ["https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"] +channels = ["https://conda.modular.com/max-nightly", "https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"] description = "A fixed-point decimal arithmetic library written in Mojo 🔥" license = "Apache-2.0" name = "decimal" @@ -13,7 +13,7 @@ version = "0.1.0" format = "magic run mojo format ./" # compile the package -package = "magic run format && magic run mojo package decimojo && cp decimojo.mojopkg ./tests/ && cp decimojo.mojopkg ./examples/ && rm decimojo.mojopkg" +package = "magic run format && magic run mojo package decimojo && cp decimojo.mojopkg ./tests/ && rm decimojo.mojopkg" p = "clear && magic run package" # debugs (run the testing files only) diff --git a/tests/test_decimal_arithmetics.mojo b/tests/test_decimal_arithmetics.mojo index 7769c7d..757a8bf 100644 --- a/tests/test_decimal_arithmetics.mojo +++ b/tests/test_decimal_arithmetics.mojo @@ -1,8 +1,8 @@ """ Test Decimal arithmetic operations including addition, subtraction, and negation. """ -from decimojo import Decimal -from decimojo.mathematics import round, absolute + +from decimojo.prelude import * import testing @@ -235,6 +235,87 @@ fn test_negation() raises: print("Decimal negation tests passed!") +fn test_abs() raises: + print("Testing decimal absolute value...") + + # Test case 1: Absolute value of positive number + var a1 = Decimal("123.45") + var result1 = abs(a1) + testing.assert_equal( + String(result1), "123.45", "Absolute value of positive number" + ) + + # Test case 2: Absolute value of negative number + var a2 = Decimal("-67.89") + var result2 = abs(a2) + testing.assert_equal( + String(result2), "67.89", "Absolute value of negative number" + ) + + # Test case 3: Absolute value of zero + var a3 = Decimal("0") + var result3 = abs(a3) + testing.assert_equal(String(result3), "0", "Absolute value of zero") + + # Test case 4: Absolute value of negative zero (if supported) + var a4 = Decimal("-0.00") + var result4 = abs(a4) + testing.assert_equal( + String(result4), "0.00", "Absolute value of negative zero" + ) + + # Test case 5: Absolute value with large number of decimal places + var a5 = Decimal("-0.0000000001") + var result5 = abs(a5) + testing.assert_equal( + String(result5), + "0.0000000001", + "Absolute value of small negative number", + ) + + # Test case 6: Absolute value of very large number + var a6 = Decimal("-9999999999.9999999999") + var result6 = abs(a6) + testing.assert_equal( + String(result6), + "9999999999.9999999999", + "Absolute value of large negative number", + ) + + # Test case 7: Absolute value of number with many significant digits + var a7 = Decimal("-0.123456789012345678901234567") + var result7 = abs(a7) + testing.assert_equal( + String(result7), + "0.123456789012345678901234567", + "Absolute value of high precision negative number", + ) + + # Test case 8: Absolute value of maximum representable number + try: + var a8 = Decimal("79228162514264337593543950335") # Maximum value + var result8 = abs(a8) + testing.assert_equal( + String(result8), + "79228162514264337593543950335", + "Absolute value of maximum value", + ) + + var a9 = Decimal( + "-79228162514264337593543950335" + ) # Negative maximum value + var result9 = abs(a9) + testing.assert_equal( + String(result9), + "79228162514264337593543950335", + "Absolute value of negative maximum value", + ) + except: + print("Maximum value test not applicable") + + print("Decimal absolute value tests passed!") + + fn test_subtraction() raises: print("Testing decimal subtraction...") @@ -1117,12 +1198,15 @@ fn main() raises: # Run addition tests test_addition() - # Run subtraction tests - test_subtraction() - # Run negation tests test_negation() + # Run absolute value tests + test_abs() + + # Run subtraction tests + test_subtraction() + # Run multiplication tests test_multiplication() @@ -1133,6 +1217,7 @@ fn main() raises: test_power_integer_exponents() # Run power tests with negative exponents + test_power_negative_exponents() # Run power tests for special cases diff --git a/tests/test_decimal_conversions.mojo b/tests/test_decimal_conversions.mojo new file mode 100644 index 0000000..844fe37 --- /dev/null +++ b/tests/test_decimal_conversions.mojo @@ -0,0 +1,126 @@ +""" +Test Decimal conversion methods: __int__, __float__, and __str__ +for different numerical cases. +""" + +from decimojo.prelude import * +import testing +import time + + +fn test_int_conversion() raises: + print("\n--- Testing Int Conversion ---") + + # Test positive integer + var d1 = Decimal("123") + var i1 = Int(d1) + print("Int(123) =", i1) + testing.assert_equal(i1, 123) + + # Test negative integer + var d2 = Decimal("-456") + var i2 = Int(d2) + print("Int(-456) =", i2) + testing.assert_equal(i2, -456) + + # Test zero + var d3 = Decimal("0") + var i3 = Int(d3) + print("Int(0) =", i3) + testing.assert_equal(i3, 0) + + # Test decimal truncation + var d4 = Decimal("789.987") + var i4 = Int(d4) + print("Int(789.987) =", i4) + testing.assert_equal(i4, 789) + + # Test negative decimal truncation + var d5 = Decimal("-123.456") + var i5 = Int(d5) + print("Int(-123.456) =", i5) + testing.assert_equal(i5, -123) + + # Test large number + var d6 = Decimal("9999999999") + var i6 = Int(d6) + print("Int(9999999999) =", i6) + testing.assert_equal(i6, 9999999999) + + +fn test_float_conversion() raises: + print("\n--- Testing Float64 Conversion ---") + + # Test positive number + var d1 = Decimal("123.456") + var f1 = Float64(d1) + print("Float64(123.456) =", f1) + testing.assert_almost_equal(f1, 123.456) + + # Test negative number + var d2 = Decimal("-789.012") + var f2 = Float64(d2) + print("Float64(-789.012) =", f2) + testing.assert_almost_equal(f2, -789.012) + + # Test zero + var d3 = Decimal("0.0") + var f3 = Float64(d3) + print("Float64(0.0) =", f3) + testing.assert_equal(f3, 0.0) + + # Test very small number + var d4 = Decimal("0.0000000001") + var f4 = Float64(d4) + print("Float64(0.0000000001) =", f4) + testing.assert_almost_equal(f4, 0.0000000001) + + # Test very large number + var d5 = Decimal("1234567890123.4567") + var f5 = Float64(d5) + print("Float64(1234567890123.4567) =", f5) + testing.assert_almost_equal(f5, 1234567890123.4567) + + +fn test_str_conversion() raises: + print("\n--- Testing String Conversion ---") + + # Test positive number + var d1 = Decimal("123.456") + var s1 = String(d1) + print("String(123.456) =", s1) + testing.assert_equal(s1, "123.456") + + # Test negative number + var d2 = Decimal("-789.012") + var s2 = String(d2) + print("String(-789.012) =", s2) + testing.assert_equal(s2, "-789.012") + + # Test zero + var d3 = Decimal("0") + var s3 = String(d3) + print("String(0) =", s3) + testing.assert_equal(s3, "0") + + # Test large number with precision + var d4 = Decimal("9876543210.0123456789") + var s4 = String(d4) + print("String(9876543210.0123456789) =", s4) + testing.assert_equal(s4, "9876543210.0123456789") + + # Test small number + var d5 = Decimal("0.0000000001") + var s5 = String(d5) + print("String(0.0000000001) =", s5) + testing.assert_equal(s5, "0.0000000001") + + +fn main() raises: + print("Starting Decimal conversion tests...") + + test_int_conversion() + test_float_conversion() + test_str_conversion() + + print("\nAll tests completed!")