note description: "DECIMAL numbers. Following the 'General Decimal Arithmetic Specification'." library: "Gobo Eiffel Decimal Arithmetic Library" copyright: "Copyright (c) 2004-2018, Paul G. Crismer and others" license: "MIT License" date: "$Date: 2019-02-07 22:54:15 +0000 (Thu, 07 Feb 2019) $" revision: "$Revision: 102807 $" class MA_DECIMAL create make_from_integer, make_from_string, make_from_string_ctx, make_copy, make_zero, make_one, make create {MA_DECIMAL} make_infinity, make_nan, make_snan, make_special create {MA_DECIMAL_TEXT_PARSER} make_from_parser feature {NONE} -- Initialization default_create -- Process instances of classes with no creation clause. -- (Default: do nothing.) -- (from ANY) do end make (a_precision: INTEGER_32) -- Create a new decimal using a_precision digits. require a_precision_positive: a_precision > 0 do create {MA_DECIMAL_COEFFICIENT_IMP} coefficient.make (a_precision) set_positive coefficient.put (0, 0) ensure zero: is_zero end make_copy (other: like Current) -- Make a copy of other. require other_not_void: other /= Void do if not other.is_special then make (other.count) copy (other) else make_special (other.special) is_negative := other.is_negative end ensure special_copy: special = other.special coefficient_copy: coefficient.is_equal (other.coefficient) sign_copy: sign = other.sign exponent_copy: exponent = other.exponent end make_from_integer (a_value: INTEGER_32) -- Make a new decimal from integer a_value. local temp_value, v, index, ten_exponent: INTEGER_32 do temp_value := a_value if a_value >= 0 then set_positive temp_value := - temp_value else set_negative end v := temp_value from ten_exponent := 0 until v = 0 loop v := Integer_.div (v, 10) if v /= 0 then ten_exponent := ten_exponent + 1 end end create {MA_DECIMAL_COEFFICIENT_IMP} coefficient.make (ten_exponent + 1) if temp_value = 0 then coefficient.put (0, 0) else from index := 0 v := temp_value until v = 0 loop coefficient.put (- Integer_.mod (v, 10), index) v := Integer_.div (v, 10) if v /= 0 then index := index + 1 end end end ensure equal_to_value: to_integer = a_value end make_from_parser (a_decimal_parser: MA_DECIMAL_TEXT_PARSER; a_context: MA_DECIMAL_CONTEXT) -- Make from a_decimal_parser, relative to a_context. require a_decimal_parser_not_void: a_decimal_parser /= Void a_context_not_void: a_context /= Void do if not attached a_decimal_parser.last_parsed as l_last_parsed or else a_decimal_parser.error then if a_context.is_extended then make_nan else make_snan end else if a_decimal_parser.is_infinity then make_infinity (Parser.sign) elseif a_decimal_parser.is_snan then make_snan elseif a_decimal_parser.is_nan then make_nan else if a_decimal_parser.sign < 0 then set_negative else set_positive end if a_decimal_parser.has_exponent then if a_decimal_parser.exponent_as_double > Platform.Maximum_integer.to_double then exponent := a_context.Maximum_exponent + a_context.digits + a_decimal_parser.exponent_count + 2 else exponent := Double_.truncated_to_integer (a_decimal_parser.exponent_as_double) end if Parser.exponent_sign < 0 then exponent := - exponent end else exponent := 0 end if a_decimal_parser.has_point then exponent := exponent - a_decimal_parser.fractional_part_count end create {MA_DECIMAL_COEFFICIENT_IMP} coefficient.make ((a_context.digits + 1).max (a_decimal_parser.coefficient_count)) coefficient.set_from_substring (l_last_parsed, a_decimal_parser.coefficient_begin, a_decimal_parser.coefficient_end) clean_up (a_context) end end end make_from_string (value_string: STRING_8) -- Make a new decimal from string value_string relative to shared_decimal_context. require value_string_not_void: value_string /= Void do make_from_string_ctx (value_string, shared_decimal_context) end make_from_string_ctx (value_string: STRING_8; ctx: MA_DECIMAL_CONTEXT) -- Make a new decimal from value_string relative to ctx. require value_string_not_void: value_string /= Void context_not_void: ctx /= Void local l_parser: like Parser do l_parser := Parser l_parser.decimal_parse (value_string) make_from_parser (l_parser, ctx) end make_infinity (a_sign: INTEGER_32) -- Make Infinity. require a_sign_valid: a_sign = -1 or else a_sign = 1 do make_special (Special_infinity) is_negative := a_sign < 0 ensure is_infinity: is_infinity sign_set: sign = a_sign end make_nan -- Make quiet 'Not a Number'. do make_special (Special_quiet_nan) ensure is_nan: is_quiet_nan end make_one -- Make one. do make (1) coefficient.put (1, 0) ensure is_one: is_one positive: not is_negative end make_snan -- Make Signaling 'Not a Number'. do make_special (Special_signaling_nan) ensure is_snan: is_signaling_nan end make_special (code_special: INTEGER_32) -- Make special from code. require valid_code_special: code_special = Special_infinity or else code_special = Special_quiet_nan or else code_special = Special_signaling_nan do coefficient := Special_coefficient special := code_special exponent := 0 ensure is_special: is_special exponent_zero: exponent = 0 end make_zero -- Make zero. do coefficient := Special_coefficient ensure zero: is_zero end feature -- Access Decimal: MA_DECIMAL_CONSTANTS -- Decimal constants -- (from MA_SHARED_DECIMAL_CONSTANTS) once create Result ensure -- from MA_SHARED_DECIMAL_CONSTANTS instance_free: class decimal_not_void: Result /= Void end Default_context: MA_DECIMAL_CONTEXT -- Default context for general purpose arithmetic -- (from MA_SHARED_DECIMAL_CONTEXT) once create Result.make_default ensure -- from MA_SHARED_DECIMAL_CONTEXT instance_free: class default_context_not_void: Result /= Void end exponent: INTEGER_32 -- Current exponent generating_type: TYPE [detachable MA_DECIMAL] -- Type of current object -- (type of which it is a direct instance) -- (from ANY) external "built_in" ensure -- from ANY generating_type_not_void: Result /= Void end generator: STRING_8 -- Name of current object's generating class -- (base class of the type of which it is a direct instance) -- (from ANY) external "built_in" ensure -- from ANY generator_not_void: Result /= Void generator_not_empty: not Result.is_empty end hash_code: INTEGER_32 -- Hash code value local i: INTEGER_32 l_exponent, l_coefficient_lsd, l_coefficient_msd: INTEGER_32 l_is_zero: BOOLEAN do l_is_zero := is_zero Result := special Result := Result + Integer_.bit_shift_left (Result, 10) Result := Integer_.bit_xor (Result, Integer_.bit_shift_right (Result, 6)) if not l_is_zero then Result := Result + sign end Result := Result + Integer_.bit_shift_left (Result, 10) Result := Integer_.bit_xor (Result, Integer_.bit_shift_right (Result, 6)) if not is_special then from l_coefficient_msd := coefficient.msd_index l_coefficient_lsd := coefficient.lower l_exponent := exponent until l_coefficient_lsd > l_coefficient_msd or else coefficient.item (l_coefficient_lsd) /= 0 loop l_coefficient_lsd := l_coefficient_lsd + 1 l_exponent := l_exponent + 1 end if not l_is_zero then Result := Result + l_exponent end Result := Result + Integer_.bit_shift_left (Result, 10) Result := Integer_.bit_xor (Result, Integer_.bit_shift_right (Result, 6)) from i := l_coefficient_lsd until i > l_coefficient_msd loop Result := Result + coefficient.item (i) Result := Result + Integer_.bit_shift_left (Result, 10) Result := Integer_.bit_xor (Result, Integer_.bit_shift_right (Result, 6)) i := i + 1 end end Result := Result + Integer_.bit_shift_left (Result, 3) Result := Integer_.bit_xor (Result, Integer_.bit_shift_right (Result, 11)) Result := Result + Integer_.bit_shift_left (Result, 15) Result := Integer_.bit_and (Result, Platform.Maximum_integer) ensure -- from HASHABLE good_hash_value: Result >= 0 end shared_decimal_context: MA_DECIMAL_CONTEXT -- Decimal context for operations where it does not explicitly appear in the signature; -- Return Default_context by default, but can be changed by calling set_shared_decimal_context -- (from MA_SHARED_DECIMAL_CONTEXT) do Result := Cell.item ensure -- from MA_SHARED_DECIMAL_CONTEXT instance_free: class shared_decimal_context_not_void: Result /= Void end sign: INTEGER_32 -- Sign: positive = 1; negative = -1 do if is_negative then Result := -1 else Result := 1 end ensure definition1: Result = -1 implies is_negative definition2: Result = 1 implies is_positive end feature {MA_DECIMAL} -- Access adjusted_exponent: INTEGER_32 -- Exponent of the most significant digit; see SDAS page 5 do Result := exponent + count - 1 ensure definition: Result = (exponent + count - 1) end feature {MA_DECIMAL, MA_DECIMAL_PARSER, MA_DECIMAL_HANDLER} -- Access coefficient: MA_DECIMAL_COEFFICIENT -- Storage for digits feature {NONE} -- Access Any_array_: KL_ARRAY_ROUTINES [detachable ANY] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class any_array_routines_not_void: Result /= Void end Array_special_integer_: KL_ARRAY_ROUTINES [detachable SPECIAL [INTEGER_32]] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class special_integer_array_routines_not_void: Result /= Void end Boolean_array_: KL_ARRAY_ROUTINES [BOOLEAN] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class boolean_array_routines_not_void: Result /= Void end Detachable_string_array_routines: KL_ARRAY_ROUTINES [detachable STRING_8] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class detachable_string_array_routines_not_void: Result /= Void end Double_: KL_DOUBLE_ROUTINES -- Routines that ought to be in class DOUBLE -- (from KL_IMPORTED_DOUBLE_ROUTINES) once create Result ensure -- from KL_IMPORTED_DOUBLE_ROUTINES instance_free: class double_routines_not_void: Result /= Void end Integer_: KL_INTEGER_ROUTINES -- Routines that ought to be in class INTEGER -- (from KL_IMPORTED_INTEGER_ROUTINES) once create Result ensure -- from KL_IMPORTED_INTEGER_ROUTINES instance_free: class integer_routines_not_void: Result /= Void end Integer_array_: KL_ARRAY_ROUTINES [INTEGER_32] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class integer_array_routines_not_void: Result /= Void end Platform: KL_PLATFORM -- Platform-dependent properties -- (from KL_SHARED_PLATFORM) once create Result ensure -- from KL_SHARED_PLATFORM instance_free: class platform_not_void: Result /= Void end String_: KL_STRING_ROUTINES -- Routines that ought to be in class STRING -- (from KL_IMPORTED_STRING_ROUTINES) once create Result ensure -- from KL_IMPORTED_STRING_ROUTINES instance_free: class string_routines_not_void: Result /= Void end String_array_: KL_ARRAY_ROUTINES [detachable STRING_8] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class string_array_routines_not_void: Result /= Void end String_array_routines: KL_ARRAY_ROUTINES [STRING_8] -- Routines that ought to be in class ARRAY -- (from KL_IMPORTED_ARRAY_ROUTINES) once create Result ensure -- from KL_IMPORTED_ARRAY_ROUTINES instance_free: class string_array_routines_not_void: Result /= Void end feature -- Measurement count: INTEGER_32 -- Count of significant digits do if is_special then Result := 0 else Result := coefficient.count end ensure zero_when_special: is_special implies Result = 0 end feature -- Comparison frozen deep_equal (a: detachable ANY; b: like arg #1): BOOLEAN -- Are a and b either both void -- or attached to isomorphic object structures? -- (from ANY) do if a = Void then Result := b = Void else Result := b /= Void and then a.is_deep_equal (b) end ensure -- from ANY instance_free: class shallow_implies_deep: standard_equal (a, b) implies Result both_or_none_void: (a = Void) implies (Result = (b = Void)) same_type: (Result and (a /= Void)) implies (b /= Void and then a.same_type (b)) symmetric: Result implies deep_equal (b, a) end frozen equal (a: detachable ANY; b: like arg #1): BOOLEAN -- Are a and b either both void or attached -- to objects considered equal? -- (from ANY) do if a = Void then Result := b = Void else Result := b /= Void and then a.is_equal (b) end ensure -- from ANY instance_free: class definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.is_equal (b)) end frozen is_deep_equal (other: MA_DECIMAL): BOOLEAN -- Are Current and other attached to isomorphic object structures? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" ensure -- from ANY shallow_implies_deep: standard_is_equal (other) implies Result same_type: Result implies same_type (other) symmetric: Result implies other.is_deep_equal (Current) end is_equal (other: like Current): BOOLEAN -- Are Current and other considered equal? require -- from ANY other_not_void: other /= Void local comparison_result: like Current do if is_nan and then other.is_nan then if is_quiet_nan then Result := other.is_quiet_nan elseif is_signaling_nan then Result := other.is_signaling_nan end elseif is_infinity and then other.is_infinity then Result := (sign = other.sign) else comparison_result := compare (other, shared_decimal_context) if comparison_result.is_zero then Result := True end end ensure -- from ANY symmetric: Result implies other ~ Current consistent: standard_is_equal (other) implies Result end is_greater alias ">" (other: MA_DECIMAL): BOOLEAN -- Is current object greater than other? -- (from KL_PART_COMPARABLE) require -- from KL_PART_COMPARABLE other_not_void: other /= Void do Result := other < Current ensure -- from KL_PART_COMPARABLE definition: Result = (other < Current) end is_greater_equal alias ">=" (other: MA_DECIMAL): BOOLEAN -- Is current object greater than or equal to other? -- (from KL_PART_COMPARABLE) require -- from KL_PART_COMPARABLE other_not_void: other /= Void do Result := (other < Current) or is_equal (other) ensure -- from KL_PART_COMPARABLE definition: Result = ((other < Current) or is_equal (other)) end is_less_equal alias "<=" (other: MA_DECIMAL): BOOLEAN -- Is current object less than or equal to other? -- (from KL_PART_COMPARABLE) require -- from KL_PART_COMPARABLE other_not_void: other /= Void do Result := (Current < other) or is_equal (other) ensure -- from KL_PART_COMPARABLE definition: Result = ((Current < other) or is_equal (other)) end frozen standard_equal (a: detachable ANY; b: like arg #1): BOOLEAN -- Are a and b either both void or attached to -- field-by-field identical objects of the same type? -- Always uses default object comparison criterion. -- (from ANY) do if a = Void then Result := b = Void else Result := b /= Void and then a.standard_is_equal (b) end ensure -- from ANY instance_free: class definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.standard_is_equal (b)) end frozen standard_is_equal (other: MA_DECIMAL): BOOLEAN -- Is other attached to an object of the same type -- as current object, and field-by-field identical to it? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" ensure -- from ANY same_type: Result implies same_type (other) symmetric: Result implies other.standard_is_equal (Current) end feature -- Status report conforms_to (other: ANY): BOOLEAN -- Does type of current object conform to type -- of other (as per Eiffel: The Language, chapter 13)? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" end divisible (other: like Current): BOOLEAN -- May current object be divided by other? require -- from NUMERIC other_exists: other /= Void do Result := not other.is_zero ensure then definition: Result = not other.is_zero end exponentiable (other: NUMERIC): BOOLEAN -- May current object be elevated to the power other? require -- from NUMERIC other_exists: other /= Void do end is_double: BOOLEAN -- Is this a double? local str: STRING_8 do str := to_scientific_string Result := str.is_double end is_hashable: BOOLEAN -- May current object be hashed? -- (True by default.) -- (from HASHABLE) do Result := True end is_infinity: BOOLEAN -- Is this an Infinity? do Result := (special = Special_infinity) end is_integer: BOOLEAN -- Is this an integer? -- (i.e no fractional part other than all zeroes) local fractional_count, index: INTEGER_32 do if is_zero then Result := True elseif exponent < 0 then if adjusted_exponent >= 0 then fractional_count := - exponent from index := fractional_count.min (count) variant index until index <= 0 or else coefficient.item (index - 1) /= 0 loop index := index - 1 end Result := index = 0 else Result := False end else Result := True end end is_nan: BOOLEAN -- Is this "Not a Number" (NaN)? do Result := is_signaling_nan or is_quiet_nan ensure definition: Result = (is_signaling_nan or is_quiet_nan) end is_negative: BOOLEAN -- Is the number negative? is_one: BOOLEAN -- Is this a One ? do if not is_special and then exponent = 0 and then coefficient.is_one then Result := True end ensure definition: Result = (not is_special and then exponent = 0 and then coefficient.is_one) end is_positive: BOOLEAN -- Is the number positive? do Result := not is_negative ensure definition: Result = not is_negative end is_quiet_nan: BOOLEAN -- Is this a "Quiet NaN"? do Result := (special = Special_quiet_nan) end is_signaling_nan: BOOLEAN -- Is this a "Signaling NaN"? do Result := (special = Special_signaling_nan) end is_special: BOOLEAN -- Is this a special value? do Result := (special /= Special_none) ensure definition: Result = (is_nan or else is_infinity) end is_zero: BOOLEAN -- Is this a Zero value? do if not is_special and then coefficient.is_zero then Result := True end ensure definition: Result = (not is_special and then coefficient.is_zero) end same_type (other: ANY): BOOLEAN -- Is type of current object identical to type of other? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" ensure -- from ANY definition: Result = (conforms_to (other) and other.conforms_to (Current)) end feature {MA_DECIMAL} -- Status setting set_quiet_nan -- Set to qNaN. do make_nan ensure qnan: is_quiet_nan end special: INTEGER_32 -- Special status feature {MA_DECIMAL, MA_DECIMAL_PARSER} -- Element change set_exponent (e: like exponent) -- Set exponent to e. do exponent := e ensure exponent_set: exponent = e end set_negative -- Set negative. do is_negative := True ensure negative: is_negative end set_positive -- Set positive. do is_negative := False ensure positive: is_positive end feature -- Conversion out: STRING_8 -- Printable representation require -- from DEBUG_OUTPUT True require -- from ANY True do create Result.make (0) Result.append_string ("[") if is_negative then Result.append_string ("1") else Result.append_string ("0") end Result.append_string (",") if is_infinity then Result.append_string ("inf") elseif is_signaling_nan then Result.append_string ("sNaN") elseif is_quiet_nan then Result.append_string ("qNaN") else Result.append_string (coefficient.out) Result.append_string (",") Result.append_string (exponent.out) end Result.append_string ("]") ensure -- from DEBUG_OUTPUT result_not_void: Result /= Void ensure -- from ANY out_not_void: Result /= Void end to_double: REAL_64 -- Current as a DOUBLE require is_double: is_double local str: STRING_8 do str := to_scientific_string Result := str.to_double end to_engineering_string: STRING_8 -- Current as a string in engineering notation format do Result := to_string_general (True) ensure to_string_not_void: Result /= Void end to_integer: INTEGER_32 -- Current as an INTEGER require is_integer: is_integer large_enough: Current >= Decimal.Minimum_integer small_enough: Current <= Decimal.Maximum_integer local ctx: MA_DECIMAL_CONTEXT do create ctx.make_double Result := to_integer_ctx (ctx) end to_integer_ctx (ctx: MA_DECIMAL_CONTEXT): INTEGER_32 -- Current as an INTEGER wrt ctx require is_integer: is_integer large_enough: Current >= Decimal.Minimum_integer small_enough: Current <= Decimal.Maximum_integer local temp: like Current index: INTEGER_32 do temp := round_to_integer (ctx) from index := temp.count - 1 Result := 0 variant index + 1 until index < 0 loop Result := Result * 10 + temp.coefficient.item (index) index := index - 1 end if is_negative then Result := - Result end end to_scientific_string: STRING_8 -- Current as a string in scientific notation format do Result := to_string_general (False) ensure to_string_not_void: Result /= Void end feature -- Duplication frozen clone (other: detachable ANY): like other obsolete "Use `twin' instead. [2017-05-31]" -- Void if other is void; otherwise new object -- equal to other -- -- For non-void other, clone calls copy; -- to change copying/cloning semantics, redefine copy. -- (from ANY) do if other /= Void then Result := other.twin end ensure -- from ANY instance_free: class equal: Result ~ other end copy (other: like Current) -- Copy other to current decimal. require -- from ANY other_not_void: other /= Void type_identity: same_type (other) do if other /= Current then if coefficient = Void or else coefficient = Special_coefficient then coefficient := other.coefficient.to_twin else coefficient.copy (other.coefficient) end exponent := other.exponent is_negative := other.is_negative special := other.special end ensure -- from ANY is_equal: Current ~ other end frozen deep_clone (other: detachable ANY): like other obsolete "Use `deep_twin' instead. [2017-05-31]" -- Void if other is void: otherwise, new object structure -- recursively duplicated from the one attached to other -- (from ANY) do if other /= Void then Result := other.deep_twin end ensure -- from ANY instance_free: class deep_equal: deep_equal (other, Result) end frozen deep_copy (other: MA_DECIMAL) -- Effect equivalent to that of: -- copy (other . deep_twin) -- (from ANY) require -- from ANY other_not_void: other /= Void do copy (other.deep_twin) ensure -- from ANY deep_equal: deep_equal (Current, other) end frozen deep_twin: MA_DECIMAL -- New object structure recursively duplicated from Current. -- (from ANY) external "built_in" ensure -- from ANY deep_twin_not_void: Result /= Void deep_equal: deep_equal (Current, Result) end frozen standard_clone (other: detachable ANY): like other obsolete "Use `standard_twin' instead. [2017-05-31]" -- Void if other is void; otherwise new object -- field-by-field identical to other. -- Always uses default copying semantics. -- (from ANY) do if other /= Void then Result := other.standard_twin end ensure -- from ANY instance_free: class equal: standard_equal (Result, other) end frozen standard_copy (other: MA_DECIMAL) -- Copy every field of other onto corresponding field -- of current object. -- (from ANY) require -- from ANY other_not_void: other /= Void type_identity: same_type (other) external "built_in" ensure -- from ANY is_standard_equal: standard_is_equal (other) end frozen standard_twin: MA_DECIMAL -- New object field-by-field identical to other. -- Always uses default copying semantics. -- (from ANY) external "built_in" ensure -- from ANY standard_twin_not_void: Result /= Void equal: standard_equal (Result, Current) end frozen twin: MA_DECIMAL -- New object equal to Current -- twin calls copy; to change copying/twinning semantics, redefine copy. -- (from ANY) external "built_in" ensure -- from ANY twin_not_void: Result /= Void is_equal: Result ~ Current end feature -- Basic operations abs: like Current -- Absolute value of Current do Result := abs_ctx (shared_decimal_context) ensure abs_not_void: Result /= Void end abs_ctx (ctx: MA_DECIMAL_CONTEXT): like Current -- Absolute value of Current relative to ctx require ctx_not_void: ctx /= Void do if is_negative then Result := minus (ctx) else Result := plus (ctx) end ensure abs_ctx_not_void: Result /= Void definition: Result.sign >= 0 end add (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Add other with respect to the ctx context require other_not_void: other /= Void ctx_not_void: ctx /= Void local operand_a, operand_b: like Current do if is_special or else other.is_special then Result := add_special (other, ctx) else create operand_a.make (ctx.digits + 1) operand_a.copy (Current) create operand_b.make (ctx.digits + 1) operand_b.copy (other) if is_negative and then other.is_positive then operand_b.unsigned_subtract (operand_a, ctx) Result := operand_b elseif is_negative and then other.is_negative then operand_a.unsigned_add (operand_b, ctx) Result := operand_a Result.set_negative elseif is_positive and then other.is_negative then operand_a.unsigned_subtract (operand_b, ctx) Result := operand_a else operand_a.unsigned_add (operand_b, ctx) Result := operand_a end if Result.is_zero then if (is_negative and then other.is_negative) or else (ctx.rounding_mode = Round_floor and then sign /= other.sign) then Result.set_negative else Result.set_positive end end Result.clean_up (ctx) end ensure add_not_void: Result /= Void end frozen as_attached: attached MA_DECIMAL obsolete "Remove calls to this feature. [2017-05-31]" -- Attached version of Current. -- (Can be used during transitional period to convert -- non-void-safe classes to void-safe ones.) -- (from ANY) do Result := Current end binary_minus alias "-" (other: like Current): like Current -- Result of subtracting other require -- from NUMERIC other_exists: other /= Void do Result := subtract (other, shared_decimal_context) ensure -- from NUMERIC result_exists: Result /= Void ensure then subtract_not_void: Result /= Void end binary_plus alias "+" (other: like Current): like Current -- Sum with other (commutative) require -- from NUMERIC other_exists: other /= Void do Result := add (other, shared_decimal_context) ensure -- from NUMERIC result_exists: Result /= Void commutative: Result ~ (other + Current) ensure then sum_not_void: Result /= Void end compare (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Compare value of Current and other; -- Result = 0 if Current = other, -- Result = -1 if Current < other, -- Result = +1 if Current > other. require other_not_void: other /= Void ctx_not_void: ctx /= Void local operand_a, operand_b: like Current temp_ctx: MA_DECIMAL_CONTEXT do if is_special or else other.is_special then if is_nan or else other.is_nan then Result := Nan if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNaN in 'compare'") end elseif is_infinity then if other.is_infinity and then is_negative = other.is_negative then Result := zero elseif is_negative then Result := Minus_one else Result := one end elseif other.is_infinity then if is_infinity and then is_negative = other.is_negative then Result := zero elseif other.is_negative then Result := one else Result := Minus_one end else Result := Nan end else create operand_a.make_copy (Current) create operand_b.make_copy (other) if is_negative /= other.is_negative then if is_zero then create operand_a.make_zero else create operand_a.make_one if is_negative then operand_a.set_negative end end if other.is_zero then create operand_b.make_zero else create operand_b.make_one if other.is_negative then operand_b.set_negative end end end temp_ctx := ctx.cloned_object temp_ctx.reset_flags Result := operand_a.subtract (operand_b, temp_ctx) if Result.is_zero and then not temp_ctx.is_flagged (Signal_subnormal) then Result := zero else if Result.is_negative then Result := Minus_one else Result := one end end end ensure compare_not_void: Result /= Void end frozen default: detachable MA_DECIMAL -- Default value of object's type -- (from ANY) do end frozen default_pointer: POINTER -- Default value of type POINTER -- (Avoid the need to write p.default for -- some p of type POINTER.) -- (from ANY) do ensure -- from ANY instance_free: class end default_rescue -- Process exception for routines with no Rescue clause. -- (Default: do nothing.) -- (from ANY) do end divide (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Divide Current by other whith respect to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void do Result := do_divide (other, ctx, Division_standard) ensure divide_not_void: Result /= Void end divide_integer (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Integer division of Current by other whith respect to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void do Result := do_divide (other, ctx, Division_integer) ensure divide_integer_not_void: Result /= Void end frozen do_nothing -- Execute a null action. -- (from ANY) do ensure -- from ANY instance_free: class end identity alias "+": like Current -- Unary plus require -- from NUMERIC True do Result := plus (shared_decimal_context) ensure -- from NUMERIC result_exists: Result /= Void ensure then unary_plus_not_void: Result /= Void end integer_quotient alias "//" (other: like Current): like Current -- Integer division do Result := divide_integer (other, shared_decimal_context) ensure integer_division_not_void: Result /= Void end integer_remainder alias "\\" (other: like Current): like Current -- Remainder of integer division do Result := remainder (other, shared_decimal_context) ensure remainder_not_void: Result /= Void end is_less alias "<" (other: like Current): BOOLEAN -- Is current decimal less than other? require -- from KL_PART_COMPARABLE other_not_void: other /= Void local res: MA_DECIMAL do res := compare (other, shared_decimal_context) if res.is_negative then Result := True end end max_ctx (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Max between Current and other relative to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void local comparison_result: MA_DECIMAL do if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNan in max") end Result := Nan else comparison_result := compare (other, ctx) if comparison_result.is_negative then Result := other else Result := Current end Result.clean_up (ctx) end ensure max_ctx_not_void: Result /= Void end min_ctx (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Min between Current and other relative to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void local comparison_result: MA_DECIMAL do if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNan in max") end Result := Nan else comparison_result := compare (other, ctx) if comparison_result.is_negative or comparison_result.is_zero then Result := Current else Result := other end Result.clean_up (ctx) end ensure min_ctx_not_void: Result /= Void end minus (ctx: MA_DECIMAL_CONTEXT): like Current -- Prefix "-" with respect to the ctx context require ctx_not_void: ctx /= Void local l_zero: like Current do create l_zero.make (ctx.digits + 1) l_zero.set_exponent (exponent) Result := l_zero.subtract (Current, ctx) ensure minus_not_void: Result /= Void end multiply (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Multiply other with respect to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void local operand_a, operand_b: like Current do if is_special or else other.is_special then if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNan in multiply") end Result := Nan elseif is_infinity or else other.is_infinity then if is_zero or else other.is_zero then ctx.signal (Signal_invalid_operation, "0 * Inf") Result := Nan else if sign = other.sign then Result := Infinity else Result := Negative_infinity end end else Result := Nan end else if is_zero or else other.is_zero then create Result.make (ctx.digits) Result.set_exponent (exponent + other.exponent) if sign = other.sign then Result.set_positive else Result.set_negative end else operand_a := Current operand_b := other create Result.make (operand_a.count + operand_b.count + 2) Result.coefficient.integer_multiply (operand_a.coefficient, operand_b.coefficient) Result.set_exponent (operand_a.exponent + operand_b.exponent) if sign = other.sign then Result.set_positive else Result.set_negative end Result.clean_up (ctx) end end ensure multiply_not_void: Result /= Void end normalize: like Current -- Normalized version of current decimal local l_count, trailing_zeroes: INTEGER_32 do Result := plus (shared_decimal_context) if Result.is_zero then Result.coefficient.keep_head (1) Result.set_exponent (0) elseif not Result.is_special then from trailing_zeroes := 0 l_count := Result.count until trailing_zeroes >= count or else Result.coefficient.item (trailing_zeroes) /= 0 loop trailing_zeroes := trailing_zeroes + 1 end if trailing_zeroes > 0 then Result.shift_right (trailing_zeroes) Result.coefficient.keep_head (Result.coefficient.msd_index + 1) end end if is_negative then Result.set_negative else Result.set_positive end ensure normalize_not_void: Result /= Void end opposite alias "-": like Current -- Unary minus require -- from NUMERIC True do Result := minus (shared_decimal_context) ensure -- from NUMERIC result_exists: Result /= Void ensure then unary_minus_not_void: Result /= Void end plus (ctx: MA_DECIMAL_CONTEXT): like Current -- Prefix "+" with respect to the ctx context require ctx_not_void: ctx /= Void local l_zero: like Current do create l_zero.make (ctx.digits + 1) l_zero.set_exponent (exponent) Result := l_zero.add (Current, ctx) ensure plus_not_void: Result /= Void end power alias "^" (other: NUMERIC): MA_DECIMAL -- Current decimal to the power other do Result := Nan end product alias "*" (other: like Current): like Current -- Product by other require -- from NUMERIC other_exists: other /= Void do Result := multiply (other, shared_decimal_context) ensure -- from NUMERIC result_exists: Result /= Void ensure then product_not_void: Result /= Void end quotient alias "/" (other: like Current): like Current -- Division by other require -- from NUMERIC other_exists: other /= Void good_divisor: divisible (other) do Result := divide (other, shared_decimal_context) ensure -- from NUMERIC result_exists: Result /= Void ensure then division_not_void: Result /= Void end remainder (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Remainder of integer division of Current by other whith respect to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void do if is_special or else other.is_special then if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNan in remainder") end Result := Nan elseif is_infinity then ctx.signal (Signal_invalid_operation, "[+-] Inf dividend in remainder") Result := Nan elseif other.is_infinity then create Result.make_copy (Current) if is_negative then Result.set_negative end else Result := Nan end else if other.is_zero then ctx.signal (Signal_invalid_operation, "Zero divisor in remainder") Result := Nan elseif is_zero then create Result.make_zero if exponent < 0 then Result.set_exponent (exponent) else Result.set_exponent (0) end if is_negative then Result.set_negative end else Result := internal_divide (other, ctx, Division_remainder) if is_negative then Result.set_negative end Result.clean_up (ctx) end end ensure remainder_not_void: Result /= Void end rescale (new_exponent: INTEGER_32; ctx: MA_DECIMAL_CONTEXT): like Current -- Decimal from Current rescaled to new_exponent require ctx_not_void: ctx /= Void local shared_digits, digits_upto_new_exponent, exponent_delta: INTEGER_32 saved_exponent_limit, result_count: INTEGER_32 do if not (new_exponent <= ctx.exponent_limit and then new_exponent >= ctx.e_tiny) then ctx.signal (Signal_invalid_operation, "new exponent is not within limits [Etiny..Emax]") Result := Nan else if is_special then create Result.make_copy (Current) Result.do_rescale_special (ctx) elseif exponent < new_exponent then if not is_zero then shared_digits := adjusted_exponent - new_exponent + 1 if shared_digits < 0 then result_count := ctx.digits + count + 1 elseif shared_digits = 0 then result_count := ctx.digits + count else result_count := ctx.digits + (count - shared_digits) end create Result.make (result_count) Result.copy (Current) Result.coefficient.set_count (result_count) Result.round (ctx) Result.strip_leading_zeroes if Result.is_underflow (ctx) then Result.do_underflow (ctx) end if ctx.is_flagged (Signal_subnormal) and then ctx.is_flagged (Signal_inexact) then ctx.signal (Signal_underflow, "Underflow when rescaling") end if Result.is_overflow (ctx) then Result.do_overflow (ctx) end if exponent > new_exponent then Result.shift_left (exponent - new_exponent) end else create Result.make_copy (Current) end Result.set_exponent (new_exponent) elseif exponent > new_exponent then if not is_zero then digits_upto_new_exponent := adjusted_exponent - new_exponent + 1 if digits_upto_new_exponent > ctx.digits then create Result.make (count + 1) Result.copy (Current) Result.shift_left (1) saved_exponent_limit := ctx.exponent_limit ctx.set_exponent_limit (count - 1) Result.set_exponent (1) Result.do_overflow (ctx) if not Result.is_special then Result.set_exponent (new_exponent) end ctx.set_exponent_limit (saved_exponent_limit) else exponent_delta := exponent - new_exponent create Result.make (count + exponent_delta) Result.copy (Current) Result.shift_left (exponent_delta) end else if new_exponent < 0 and then exponent < 0 and then count > 1 then digits_upto_new_exponent := - new_exponent + 1 else digits_upto_new_exponent := 1 end if digits_upto_new_exponent > ctx.digits then create Result.make (count + 1) Result.copy (Current) Result.shift_left (1) saved_exponent_limit := ctx.exponent_limit ctx.set_exponent_limit (Result.adjusted_exponent - 1) Result.do_overflow (ctx) ctx.set_exponent_limit (saved_exponent_limit) else if digits_upto_new_exponent > 1 then exponent_delta := exponent - new_exponent create Result.make (count + exponent_delta) Result.copy (Current) Result.shift_left (exponent_delta) else create Result.make_copy (Current) end Result.set_exponent (new_exponent) end end Result.clean_up (ctx) else create Result.make_copy (Current) Result.clean_up (ctx) end end ensure rescale_not_void: Result /= Void end rescale_decimal (new_exponent: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Rescale using decimal new_exponent require new_exponent_not_void: new_exponent /= Void ctx_not_void: ctx /= Void local e_max, e_min: MA_DECIMAL new_integer_exponent: INTEGER_32 temp_ctx: MA_DECIMAL_CONTEXT do if new_exponent.is_special or else is_special then if new_exponent.is_signaling_nan or else is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNaN as new exponent in 'rescale_decimal'") Result := Nan elseif new_exponent.is_quiet_nan then Result := Nan elseif new_exponent.is_infinity then ctx.signal (Signal_invalid_operation, "Inf as new exponent in 'rescale_decimal'") Result := Nan else create Result.make_copy (Current) Result.do_rescale_special (ctx) end else create e_max.make_from_integer (ctx.exponent_limit) create e_min.make_from_integer (ctx.e_tiny) if new_exponent <= e_max and then new_exponent >= e_min then create temp_ctx.make_double if new_exponent.is_integer then new_integer_exponent := new_exponent.to_integer_ctx (temp_ctx) if new_integer_exponent <= ctx.exponent_limit and then new_integer_exponent >= ctx.e_tiny then Result := rescale (new_integer_exponent, ctx) else ctx.signal (Signal_invalid_operation, "new exponent is not within limits [Etiny..Emax]") Result := Nan end else ctx.signal (Signal_invalid_operation, "new exponent has fractional part in 'rescale_decimal'") Result := Nan end else ctx.signal (Signal_invalid_operation, "new exponent if not within limits [Etiny..Emax]") Result := Nan end end ensure rescale_decimal_not_void: Result /= Void end round_to_integer (ctx: MA_DECIMAL_CONTEXT): like Current -- Round to an integer with exponent 0 require ctx_not_void: ctx /= Void do Result := rescale (0, ctx) ensure round_to_integer_not_void: Result /= Void definition: not Result.is_special implies Result.exponent = 0 end subtract (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Subtract other with respect to the ctx context require other_not_void: other /= Void ctx_not_void: ctx /= Void local operand_b: like Current do if is_special or else other.is_special then Result := subtract_special (other, ctx) else create operand_b.make_copy (other) if operand_b.is_positive then operand_b.set_negative else operand_b.set_positive end Result := add (operand_b, ctx) end ensure subtract_not_void: Result /= Void end feature {MA_DECIMAL} -- Basic operations add_special (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Add special numbers. require other_not_void: other /= Void special: is_special or else other.is_special ctx_not_void: ctx /= Void do if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNaN operand in add") end Result := Nan elseif is_infinity and then other.is_infinity then if sign /= other.sign then ctx.signal (Signal_invalid_operation, "+Inf and -Inf operands in add") Result := Nan else if is_negative then Result := Negative_infinity else Result := Infinity end end elseif is_infinity or else other.is_infinity then if is_infinity then if is_negative then Result := Negative_infinity else Result := Infinity end else if other.is_negative then Result := Negative_infinity else Result := Infinity end end else Result := Nan end ensure add_special_not_void: Result /= Void end align_and_hint (other: like Current; precision: INTEGER_32): INTEGER_32 -- Align Current and other with respect to precision -- and give hint for further operations local new_count, new_exponent: INTEGER_32 limited_precision: BOOLEAN shift_count: INTEGER_32 do limited_precision := (precision > 0) if exponent = other.exponent then new_count := count.max (other.count) if new_count > count then grow (new_count) end if new_count > other.count then other.grow (new_count) end Result := Align_hint_both elseif exponent > other.exponent then new_exponent := exponent.min (adjusted_exponent - (precision + 1)) if new_exponent > other.adjusted_exponent then if is_zero then Result := Align_hint_other_zero else if limited_precision then if other.is_zero then Result := Align_hint_current_zero else Result := Align_hint_current end shift_count := precision + 1 - count if shift_count > 0 then shift_left (shift_count) end end end else if limited_precision then align_overlapped (other, precision) else align_unlimited (other) end Result := Align_hint_both end else new_exponent := other.exponent.min (other.adjusted_exponent - (precision + 1)) if new_exponent > adjusted_exponent then if other.is_zero then Result := Align_hint_current_zero else if limited_precision then if is_zero then Result := Align_hint_other_zero else Result := Align_hint_other end shift_count := precision + 1 - other.count if shift_count > 0 then other.shift_left (shift_count) end end end else if limited_precision then other.align_overlapped (Current, precision) else other.align_unlimited (Current) end Result := Align_hint_both end end ensure hint_both_is_same_count: Result = Align_hint_both implies count = other.count hint_both_is_same_exponent: Result = Align_hint_both implies exponent = other.exponent end align_overlapped (other: like Current; precision: INTEGER_32) -- Align overlapping numbers. require other_not_void: other /= Void exponent_greater: exponent > other.exponent local exponent_delta, new_digits: INTEGER_32 do exponent_delta := exponent - other.exponent if exponent_delta > 0 then shift_left (exponent_delta) end new_digits := count.max (other.count) if new_digits > other.count then other.grow (new_digits) end if new_digits > count then grow (new_digits) end ensure same_count: count = other.count same_exponent: exponent = other.exponent end align_unlimited (other: like Current) -- Align unlimited. require other_not_void: other /= Void exponent_greater: exponent > other.exponent local count_alignment: INTEGER_32 do shift_left (exponent - other.exponent) count_alignment := count - other.count if count_alignment > 0 then other.grow (count) elseif count_alignment < 0 then grow (other.count) end ensure same_count: count = other.count same_exponent: exponent = other.exponent end clean_up (ctx: MA_DECIMAL_CONTEXT) -- Clean up Current wrt ctx, rounding it if necessary. require ctx_not_void: ctx /= Void local lost_digits_trap, lost_digits_flag: BOOLEAN do if not is_special then lost_digits_trap := ctx.is_trapped (Signal_lost_digits) lost_digits_flag := ctx.is_flagged (Signal_lost_digits) ctx.disable_trap (Signal_lost_digits) ctx.reset_flag (Signal_lost_digits) strip_leading_zeroes if is_underflow (ctx) then do_underflow (ctx) else if ctx.digits > 0 and then count > ctx.digits then round (ctx) end if is_overflow (ctx) then do_overflow (ctx) end end if lost_digits_trap then ctx.enable_trap (Signal_lost_digits) end if lost_digits_flag or else ctx.is_flagged (Signal_lost_digits) then ctx.set_flag (Signal_lost_digits) else ctx.reset_flag (Signal_lost_digits) end end end Division_integer: INTEGER_32 = 2 Division_remainder: INTEGER_32 = 3 -- Division types Division_standard: INTEGER_32 = 1 do_divide (other: like Current; ctx: MA_DECIMAL_CONTEXT; division_type: INTEGER_32): like Current -- Do a division_type of Current by other require other_not_void: other /= Void ctx_not_void: ctx /= Void local integer_division: BOOLEAN do integer_division := (division_type = Division_integer) or else (division_type = Division_remainder) if is_special or else other.is_special then if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNan in divide") end Result := Nan elseif is_infinity and then other.is_infinity then ctx.signal (Signal_invalid_operation, "[+-] Inf / [+-] Inf") Result := Nan elseif is_infinity then if sign = other.sign then Result := Infinity else Result := Negative_infinity end if other.is_zero then ctx.signal (Signal_division_by_zero, "[+-] Inf / [+-] 0") end elseif other.is_infinity then if sign = other.sign then Result := zero else Result := Negative_zero end else Result := Nan end else if other.is_zero then if is_zero then ctx.signal (Signal_invalid_operation, "Division Undefined : O/O") Result := Nan else ctx.signal (Signal_division_by_zero, "Division by zero") if sign = other.sign then Result := Infinity else Result := Negative_infinity end end elseif is_zero then create Result.make_zero if integer_division then Result.set_exponent (0) else Result.set_exponent (exponent - other.adjusted_exponent) end if sign = other.sign then Result.set_positive else Result.set_negative end Result.clean_up (ctx) else Result := internal_divide (other, ctx, division_type) if sign = other.sign then Result.set_positive else Result.set_negative end Result.clean_up (ctx) end end ensure divide_not_void: Result /= Void end do_overflow (ctx: MA_DECIMAL_CONTEXT) -- Do overflow. require ctx_not_void: ctx /= Void overflow: is_overflow (ctx) do if not is_zero then ctx.signal (Signal_overflow, "") inspect ctx.rounding_mode when Round_half_up, Round_half_even, Round_half_down, Round_up then promote_to_infinity (sign) when Round_down then set_largest (ctx) when Round_ceiling then if is_negative then set_largest (ctx) else promote_to_infinity (sign) end when Round_floor then if is_positive then set_largest (ctx) else promote_to_infinity (sign) end end ctx.signal (Signal_inexact, "do_overflow") ctx.signal (Signal_rounded, "do_overflow") else set_exponent (ctx.exponent_limit) end end do_rescale_special (ctx: MA_DECIMAL_CONTEXT) -- Rescale special numbers. require is_special: is_special not_constant_infinity: Current /= Infinity not_constant_negative_infinity: Current /= Negative_infinity not_constant_nan: Current /= Nan not_constant_snan: Current /= Snan do if is_quiet_nan then elseif is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNaN as operand in rescale") set_quiet_nan elseif is_infinity then end end do_round_ceiling (ctx: MA_DECIMAL_CONTEXT) -- Round to a more positive number. require ctx_not_void: ctx /= Void do if is_negative or else not lost_digits (ctx) then do_round_down (ctx) else do_round_up (ctx) end end do_round_down (ctx: MA_DECIMAL_CONTEXT) -- Round towards zero. require ctx_not_void: ctx /= Void positive_precision: ctx.digits >= 1 local exponent_increment: INTEGER_32 l_count: INTEGER_32 do l_count := count - ctx.digits coefficient.shift_right (l_count) exponent_increment := l_count exponent := exponent + exponent_increment coefficient.keep_head (ctx.digits) end do_round_floor (ctx: MA_DECIMAL_CONTEXT) -- Round to a more negative number. require ctx_not_void: ctx /= Void do if is_positive or else not lost_digits (ctx) then do_round_down (ctx) else do_round_up (ctx) end end do_round_half_down (ctx: MA_DECIMAL_CONTEXT) -- Round to nearest neighbor, where an equidistant value is rounded down. -- If the discarded digits represent greater than half (0.5 times) -- the value of a one in the next position then the result should be -- rounded up (away from zero). Otherwise the discarded digits are ignored. require ctx_not_void: ctx /= Void do inspect three_way_compare_discarded_to_half (ctx) when -1 then do_round_down (ctx) when 1 then do_round_up (ctx) else do_round_down (ctx) end end do_round_half_even (ctx: MA_DECIMAL_CONTEXT) -- Round to nearest neighbor, where an equidistant value is rounded to the nearest even neighbor. -- If the discarded digits represent greater than half (0.5 times) the value of a one in the -- next position then the result should be rounded up (away from zero). -- If they represent less than half, then the result should be rounded down. -- Otherwise (they represent exactly half) the result is rounded down if its rightmost digit -- is even, or rounded up if its rightmost digit is odd (to make an even digit). require ctx_not_void: ctx /= Void do inspect three_way_compare_discarded_to_half (ctx) when -1 then do_round_down (ctx) when 1 then do_round_up (ctx) else if (coefficient.item (count - ctx.digits) \\ 2 = 0) then do_round_down (ctx) else do_round_up (ctx) end end end do_round_half_up (ctx: MA_DECIMAL_CONTEXT) -- Round to nearest neighbor, where an equidistant value is rounded up. -- If the discarded digits represent greater than or equal to half (0.5 times) the value -- of a one in the next position then the result should be rounded up (away from zero). -- Otherwise the discarded digits are ignored. require ctx_not_void: ctx /= Void do inspect three_way_compare_discarded_to_half (ctx) when 1, 0 then do_round_up (ctx) else do_round_down (ctx) end end do_round_up (ctx: MA_DECIMAL_CONTEXT) -- Round away from zero. require ctx_not_void: ctx /= Void local old_count, exponent_increment: INTEGER_32 do if lost_digits (ctx) then old_count := count coefficient.integer_quick_add_msd (1, ctx.digits) exponent_increment := old_count - ctx.digits exponent := exponent + exponent_increment end if count > ctx.digits then shift_right (count - ctx.digits) coefficient.keep_head (ctx.digits) end end do_underflow (ctx: MA_DECIMAL_CONTEXT) -- Do underflow. require ctx_not_void: ctx /= Void underflow: is_underflow (ctx) local e_tiny, shared_digits, subnormal_count, count_upto_elimit, saved_digits: INTEGER_32 l_is_zero, l_was_rounded: BOOLEAN l_reason: detachable STRING_8 value: INTEGER_32 do l_is_zero := is_zero if not l_is_zero then ctx.signal (Signal_subnormal, "") else l_was_rounded := ctx.is_flagged (Signal_rounded) l_reason := ctx.reason end e_tiny := ctx.e_tiny if exponent < e_tiny then saved_digits := ctx.digits shared_digits := adjusted_exponent - e_tiny + 1 if shared_digits < 0 then saved_digits := ctx.digits ctx.force_digits (coefficient.count - 1) value := 0 inspect ctx.rounding_mode when Round_up then value := 1 when Round_ceiling then if is_positive and then lost_digits (ctx) then value := 1 end when Round_floor then if is_positive or else not lost_digits (ctx) then value := 0 else value := 1 end else value := 0 end ctx.set_digits (saved_digits) coefficient.put (value, 0) coefficient.keep_head (1) exponent := e_tiny ctx.signal (Signal_inexact, "Rescaling to e_tiny") ctx.signal (Signal_rounded, "Rescaling to e_tiny") ctx.signal (Signal_underflow, "Rescaling to e_tiny") else if shared_digits = 0 then ctx.set_digits (1) grow (count + 1) else check end count_upto_elimit := - ctx.exponent_limit - exponent + 1 if count < count_upto_elimit then grow (count_upto_elimit) end subnormal_count := - ctx.exponent_limit - e_tiny + 1 ctx.set_digits (subnormal_count) end round (ctx) ctx.set_digits (saved_digits) strip_leading_zeroes if ctx.is_flagged (Signal_subnormal) and then ctx.is_flagged (Signal_inexact) then ctx.signal (Signal_underflow, "Underflow when rescaling") end if is_overflow (ctx) then do_overflow (ctx) end end exponent := e_tiny if l_is_zero then if l_was_rounded and then l_reason /= Void then ctx.signal (Signal_rounded, l_reason) else ctx.reset_flag (Signal_rounded) end end end end grow (a_count: INTEGER_32) -- Grow coefficient so that it can accommodate a_count digits. require not_special: not is_special a_count_greater_zero: a_count > 0 a_count_less_10_000: a_count < 10000 do coefficient.grow (a_count) ensure count_set: count = a_count end internal_divide (other: like Current; ctx: MA_DECIMAL_CONTEXT; division_type: INTEGER_32): like Current -- Divide Current by other whith respect to ctx require other_not_void: other /= Void ctx_not_void: ctx /= Void local dividend, divisor, local_remainder: like Current adjust, divisor_adjust, dividend_adjust, current_digit_exponent, new_exponent: INTEGER_32 original_dividend_exponent, original_divisor_exponent, bias: INTEGER_32 done, integer_division, impossible, is_negative_exponent, dividend_is_zero: BOOLEAN do integer_division := (division_type /= Division_standard) create dividend.make_copy (Current) create divisor.make_copy (other) original_divisor_exponent := divisor.exponent original_dividend_exponent := dividend.exponent if dividend.is_zero then dividend_is_zero := True end create Result.make (ctx.digits + 1) adjust := 0 divisor_adjust := 0 dividend_adjust := 0 from until dividend.coefficient >= divisor.coefficient loop dividend.shift_left (1) adjust := adjust + 1 dividend_adjust := dividend_adjust + 1 end check dividend.coefficient >= divisor.coefficient end from divisor.shift_left (1) until dividend.coefficient < divisor.coefficient loop adjust := adjust - 1 divisor.shift_left (1) divisor_adjust := divisor_adjust + 1 end check dividend.coefficient < divisor.coefficient end divisor.shift_right (1) divisor.coefficient.keep_head (divisor.coefficient.count - 1) from if integer_division then current_digit_exponent := (original_dividend_exponent - (original_divisor_exponent + adjust)) impossible := (current_digit_exponent >= ctx.digits) is_negative_exponent := (current_digit_exponent) < 0 done := is_negative_exponent or else impossible else impossible := False done := False end if not done then Result.coefficient.grow (ctx.digits + 1) Result.coefficient.keep_head (1) end until done loop from until divisor.coefficient > dividend.coefficient loop dividend.coefficient.integer_subtract (divisor.coefficient) Result.coefficient.integer_quick_add_msd (1, Result.count) end inspect division_type when Division_standard then if (dividend.is_zero and then adjust >= 0) or else (Result.count = ctx.digits) then done := True end else if current_digit_exponent = 0 then done := True end end if not done then Result.coefficient.shift_left (1) dividend.coefficient.shift_left (1) adjust := adjust + 1 current_digit_exponent := current_digit_exponent - 1 end end if impossible then Result.set_quiet_nan ctx.signal (Signal_invalid_operation, "Division impossible") else local_remainder := dividend inspect division_type when Division_standard then if local_remainder.is_zero then if adjust < 0 then ctx.signal (Signal_rounded, "Artificial rounding in division where remainder is zero") end else Result.coefficient.shift_left (1) adjust := adjust + 1 divisor.coefficient.integer_subtract (local_remainder.coefficient) inspect divisor.coefficient.three_way_comparison (local_remainder.coefficient) when 0 then Result.coefficient.put (5, 0) when 1 then Result.coefficient.put (4, 0) else Result.coefficient.put (6, 0) end end if dividend.is_zero then Result.set_exponent (original_dividend_exponent - (original_divisor_exponent + adjust)) else Result.set_exponent (exponent - (original_divisor_exponent + adjust)) end when Division_integer then Result.set_exponent (0) else Result := local_remainder if is_negative_exponent then create Result.make_copy (Current) else new_exponent := original_dividend_exponent.min (original_divisor_exponent) bias := new_exponent - (dividend.exponent.min (divisor.exponent)) if Result.is_zero then if dividend_is_zero then new_exponent := original_dividend_exponent elseif new_exponent >= 0 then new_exponent := 0 else new_exponent := exponent - (original_divisor_exponent + adjust) end else if bias /= 0 then Result.coefficient.shift_right (bias.abs) end end Result.set_exponent (new_exponent) end end end ensure divide_not_void: Result /= Void end is_overflow (ctx: MA_DECIMAL_CONTEXT): BOOLEAN -- Is there an overflow condition wrt ctx? require ctx_not_void: ctx /= Void do Result := adjusted_exponent > ctx.exponent_limit ensure definition: Result = (adjusted_exponent > ctx.exponent_limit) end is_underflow (ctx: MA_DECIMAL_CONTEXT): BOOLEAN -- Is there an underflow condition wrt ctx? require ctx_not_void: ctx /= Void do Result := adjusted_exponent < - ctx.exponent_limit ensure definition: Result = (adjusted_exponent < - ctx.exponent_limit) end lost_digits (ctx: MA_DECIMAL_CONTEXT): BOOLEAN -- Should Current loose digits if rounded wrt ctx? require ctx_not_void: ctx /= Void local index: INTEGER_32 do from index := count - ctx.digits - 1 until index < 0 or else coefficient.item (index) /= 0 loop index := index - 1 end Result := index >= 0 ensure definition1: (count - ctx.digits - 1) >= 0 implies Result = (coefficient.subcoefficient (0, count - ctx.digits - 1)).is_significant definition2: (count - ctx.digits - 1) < 0 implies not Result end promote_to_infinity (a_sign: INTEGER_32) -- Promote to infinity. do make_infinity (a_sign) ensure infinity: is_infinity sign_set: sign = a_sign end round (ctx: MA_DECIMAL_CONTEXT) -- Round Current according to ctx.rounding_mode. require not_special: not is_special roundable: ctx.digits > 0 and then count > ctx.digits do if is_special then if is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNaN in 'round'") end elseif count > ctx.digits then ctx.signal (Signal_rounded, "Argument rounded") if lost_digits (ctx) then ctx.signal (Signal_inexact, "Inexact when rouding") end inspect ctx.rounding_mode when Round_up then do_round_up (ctx) when Round_down then do_round_down (ctx) when Round_ceiling then do_round_ceiling (ctx) when Round_floor then do_round_floor (ctx) when Round_half_up then do_round_half_up (ctx) when Round_half_down then do_round_half_down (ctx) when Round_half_even then do_round_half_even (ctx) else end end ensure rounded: count <= ctx.digits end set_largest (ctx: MA_DECIMAL_CONTEXT) -- Set to largest finite number that can be represented with ctx.precision. require ctx_not_void: ctx /= Void local index: INTEGER_32 do if count < ctx.digits then grow (ctx.digits) end from index := 0 until index >= count loop coefficient.put (9, index) index := index + 1 end coefficient.keep_head (ctx.digits) if exponent < 0 then exponent := - ctx.exponent_limit + (count - 1) else exponent := ctx.exponent_limit - (count - 1) end end shift_left (a_count: INTEGER_32) -- Shift the coefficient left a_count position and adjust exponent. -- value still must be the same as with the original exponent. require not_special: not is_special a_count_positive: a_count > 0 do coefficient.shift_left (a_count) exponent := exponent - a_count ensure count_adapted: count = old count + a_count exponent_adapted: exponent = old exponent - a_count end shift_right (a_count: INTEGER_32) -- Shift the coefficient right a_count position and adjust exponent. -- Digits are lost. require not_special: not is_special a_count_positive: a_count > 0 do coefficient.shift_right (a_count) exponent := exponent + a_count ensure exponent_adapted: exponent = old exponent + a_count end strip_leading_zeroes -- Strip leading zeroes. require not_special: not is_special do coefficient.strip_leading_zeroes end subtract_special (other: like Current; ctx: MA_DECIMAL_CONTEXT): like Current -- Subtract special numbers. require other_not_void: other /= Void special: is_special or else other.is_special ctx_not_void: ctx /= Void do if is_nan or else other.is_nan then if is_signaling_nan or else other.is_signaling_nan then ctx.signal (Signal_invalid_operation, "sNaN operand in subtract") end Result := Nan elseif is_infinity and then other.is_infinity then if sign = other.sign then ctx.signal (Signal_invalid_operation, "Inf and Inf operands in subtract") Result := Nan else if is_negative then Result := Negative_infinity else Result := Infinity end end elseif is_infinity or else other.is_infinity then Result := Infinity if is_infinity then if is_negative then Result := Negative_infinity end else if other.is_positive then Result := Negative_infinity else Result := Infinity end end else Result := Nan end ensure subtract_special_not_void: Result /= Void end three_way_compare_discarded_to_half (ctx: MA_DECIMAL_CONTEXT): INTEGER_32 -- Compare discarded digits greater than 0.5 require ctx_not_void: ctx /= Void local digit, index: INTEGER_32 do digit := coefficient.item (count - ctx.digits - 1) if digit > 5 then Result := 1 elseif digit < 5 then Result := -1 else index := count - ctx.digits - 2 from until index < 0 or else coefficient.item (index) /= 0 loop index := index - 1 end if index >= 0 then Result := 1 else Result := 0 end end ensure definition: Result >= -1 and then Result <= 1 end to_string_general (is_engineering: BOOLEAN): STRING_8 -- Current as a number in engineering notation if is_engineering -- is True, in scientific notation otherwise. local str_coefficient: STRING_8 str_zero_pad: STRING_8 index, after_point_count, the_exponent, printed_exponent, exponent_difference: INTEGER_32 digits_before_point: INTEGER_32 exponential: BOOLEAN do create Result.make (0) if is_special then if is_quiet_nan then Result.append_string ("NaN") elseif is_signaling_nan then Result.append_string ("sNaN") else if is_negative then Result.append_string ("-") end Result.append_string ("Infinity") end else if is_negative then Result.append_string ("-") end create str_coefficient.make (count) from index := count - 1 until index < 0 loop str_coefficient.append_character (Integer_.to_character (('0').code + coefficient.item (index))) index := index - 1 end the_exponent := adjusted_exponent exponential := not (exponent <= 0 and then adjusted_exponent >= -6) if exponential then printed_exponent := the_exponent if is_engineering then from until printed_exponent \\ 3 = 0 loop printed_exponent := printed_exponent - 1 end exponent_difference := the_exponent - printed_exponent if not is_zero then digits_before_point := 1 + exponent_difference from until str_coefficient.count >= digits_before_point loop str_coefficient.append_character ('0') end else digits_before_point := 1 end else digits_before_point := 1 end if str_coefficient.count > digits_before_point then Result.append_string (str_coefficient.substring (1, digits_before_point)) Result.append_character ('.') Result.append_string (str_coefficient.substring (digits_before_point + 1, str_coefficient.count)) else Result.append_string (str_coefficient) end if printed_exponent /= 0 then Result.append_character ('E') if the_exponent < 0 then Result.append_character ('-') else Result.append_character ('+') end Result.append_string ((printed_exponent.abs).out) end else if exponent < 0 then after_point_count := exponent.abs if after_point_count > str_coefficient.count then create str_zero_pad.make_filled ('0', after_point_count - str_coefficient.count) Result.append_string ("0.") Result.append_string (str_zero_pad) Result.append_string (str_coefficient) elseif after_point_count = str_coefficient.count then Result.append_string ("0.") Result.append_string (str_coefficient) else Result.append_string (str_coefficient.substring (1, str_coefficient.count - after_point_count)) Result.append_string (".") Result.append_string (str_coefficient.substring (str_coefficient.count - after_point_count + 1, str_coefficient.count)) end else Result.append_string (str_coefficient) end end end ensure to_string_not_void: Result /= Void end unsigned_add (other: like Current; ctx: MA_DECIMAL_CONTEXT) -- Add other to Current. -- Note: this will alter other and Current. require other_not_void: other /= Void ctx_not_void: ctx /= Void local align_hint: INTEGER_32 msd: INTEGER_32 do align_hint := align_and_hint (other, ctx.digits) if align_hint = Align_hint_current then shift_left (ctx.digits + 2 - count) coefficient.put (other.coefficient.item (other.coefficient.msd_index), 0) ctx.signal (Signal_inexact, "") elseif align_hint = Align_hint_other then msd := coefficient.item (coefficient.msd_index) copy (other) shift_left (ctx.digits + 2 - count) coefficient.put (msd, 0) ctx.signal (Signal_inexact, "") elseif align_hint = Align_hint_other_zero then copy (other) elseif align_hint = Align_hint_current_zero then else coefficient.integer_add (other.coefficient) exponent := exponent.min (other.exponent) end end unsigned_subtract (other: like Current; ctx: MA_DECIMAL_CONTEXT) -- Subtract other without taking the sign into account. require other_not_void: other /= Void ctx_not_void: ctx /= Void local test, align_hint: INTEGER_32 do align_hint := align_and_hint (other, ctx.digits) if align_hint = Align_hint_current then shift_left (ctx.digits + 2 - count) coefficient.integer_quick_subtract_msd (1, coefficient.count) elseif align_hint = Align_hint_other then copy (other) shift_left (ctx.digits + 2 - count) coefficient.integer_quick_subtract_msd (1, coefficient.count) set_negative elseif align_hint = Align_hint_current_zero then elseif align_hint = Align_hint_other_zero then copy (other) set_negative else test := coefficient.three_way_comparison (other.coefficient) if test = 0 then coefficient.keep_head (1) coefficient.put (0, 0) elseif test > 0 then coefficient.integer_subtract (other.coefficient) else other.coefficient.integer_subtract (coefficient) coefficient.copy (other.coefficient) set_negative end exponent := exponent.min (other.exponent) end end feature {NONE} -- Implementation Cell: KL_CELL [MA_DECIMAL_CONTEXT] -- Cell containing shared decimal context -- (from MA_SHARED_DECIMAL_CONTEXT) once create Result.make (Default_context) ensure -- from MA_SHARED_DECIMAL_CONTEXT instance_free: class cell_not_void: Result /= Void context_not_void: Cell.item /= Void end Once_one: MA_DECIMAL -- Shared One once create Result.make_one ensure instance_free: class one_not_void: Result /= Void is_one: Result.is_one end Once_zero: MA_DECIMAL -- Shared Zero once create Result.make_zero ensure instance_free: class zero_not_void: Result /= Void is_zero: Result.is_zero end Parser: MA_DECIMAL_TEXT_PARSER -- Decimal text parser once create Result.make ensure parser_not_void: Result /= Void end Special_coefficient: MA_DECIMAL_COEFFICIENT once create {MA_DECIMAL_COEFFICIENT_IMP} Result.make (1) Result.put (0, 0) ensure instance_free: class special_coefficient_not_void: Result /= Void zero: Result.is_zero end feature -- Constants Infinity: MA_DECIMAL -- Infinity once create Result.make_infinity (1) ensure instance_free: class infinity_not_void: Result /= Void is_infinity: Result.is_infinity is_positive: Result.is_positive end Minus_one: MA_DECIMAL -- Minus one once create Result.make_copy (one) Result.set_negative ensure instance_free: class minus_one_not_void: Result /= Void is_minus_one: Result.is_one and then Result.is_negative end Nan: MA_DECIMAL -- Not a Number once create Result.make_nan ensure instance_free: class nan_not_void: Result /= Void is_nan: Result.is_nan end Negative_infinity: MA_DECIMAL -- Negative infinity once create Result.make_infinity (-1) ensure instance_free: class negative_infinity_not_void: Result /= Void is_infinity: Result.is_infinity is_negative: Result.is_negative end Negative_zero: MA_DECIMAL -- Negative zero once create Result.make_zero Result.set_negative ensure instance_free: class negative_zero_not_void: Result /= Void is_zero: Result.is_zero is_negative: Result.is_negative end one: like Current -- Neutral element for "*" and "/" require -- from NUMERIC True do Result := Once_one ensure -- from NUMERIC result_exists: Result /= Void ensure then instance_free: class one_is_one: Result.is_one one_is_positive: not Result.is_negative end Snan: MA_DECIMAL -- Signaling Not a Number once create Result.make_snan ensure instance_free: class snan_not_void: Result /= Void is_snan: Result.is_signaling_nan end zero: like Current -- Neutral element for "+" and "-" require -- from NUMERIC True do Result := Once_zero ensure -- from NUMERIC result_exists: Result /= Void ensure then instance_free: class is_zero: Result.is_zero end feature {NONE} -- Constants Align_hint_both: INTEGER_32 = 3 Align_hint_current: INTEGER_32 = 1 Align_hint_current_zero: INTEGER_32 = 4 Align_hint_other: INTEGER_32 = 2 Align_hint_other_zero: INTEGER_32 = 5 feature {NONE} -- Constants: defaults Default_digits: INTEGER_32 = 9 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Default_rounding_mode: INTEGER_32 -- Default rounding mode -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := Round_half_up ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class definition: Result = Round_half_up end Default_traps: ARRAY [INTEGER_32] -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := <<Signal_division_by_zero, Signal_invalid_operation, Signal_overflow, Signal_underflow>> ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class default_traps_not_void: Result /= Void has_division_by_zero: Integer_array_.has (Result, Signal_division_by_zero) has_invalid_operation: Integer_array_.has (Result, Signal_invalid_operation) has_overflow: Integer_array_.has (Result, Signal_overflow) has_underflow: Integer_array_.has (Result, Signal_underflow) end feature {NONE} -- Constants: limits Maximum_digits: INTEGER_32 = 999999999 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Maximum_exponent: INTEGER_32 = 999999999 -- Maximum exponent allowed -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Maximum_integer_as_decimal: MA_DECIMAL obsolete "Use MA_DECIMAL_CONSTANTS.maximum_integer instead. [2005-09-11]" -- Maximum value convertible to integer -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := Decimal.Maximum_integer ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class maximum_integer_not_void: Result /= Void end Minimum_digits: INTEGER_32 = 1 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Minimum_exponent: INTEGER_32 = -999999999 -- Minimum exponent allowed -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Minimum_integer_as_decimal: MA_DECIMAL obsolete "Use MA_DECIMAL_CONSTANTS.minimum_integer instead. [2005-09-11]" -- Minimum value convertible to integer -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := Decimal.Minimum_integer ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class minimum_integer_not_void: Result /= Void end feature {NONE} -- Constants: rounding modes Round_ceiling: INTEGER_32 = 2 -- Rounding mode to round to a more positive number; -- All discarded digits are ignored (truncated). The result is neither incremented nor decremented. -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_down: INTEGER_32 = 1 -- Rounding mode to round towards zero; -- If any of the discarded digits are non-zero then the result should be rounded towards the next ore negative digit. -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_floor: INTEGER_32 = 3 -- Rounding mode to round to a more negative number; -- If any of the discarded digits are non-zero then the result should be rounded towards the next more negative digit. -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_half_down: INTEGER_32 = 5 -- Rounding mode to round to nearest neighbor, where an equidistant value is rounded down; -- If the discarded digits represent greater than half (0.5 times) -- the value of a one in the next position then the result should be -- rounded up (away from zero). Otherwise the discarded digits are ignored. -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_half_even: INTEGER_32 = 6 -- Rounding mode to round to nearest neighbor, where an equidistant value is rounded to the nearest even neighbor; -- If the discarded digits represent greater than half (0.5 times) the value of a one in the next position then the result should be -- rounded up (away from zero). -- If they represent less than half, then the result should be rounded down. -- Otherwise (they represent exactly half) the result is rounded down if its rightmost digit is even, or rounded up if its -- rightmost digit is odd (to make an even digit). -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_half_up: INTEGER_32 = 4 -- Rounding mode to round to nearest neighbor, where an equidistant value is rounded up; -- If the discarded digits represent greater than or equal to half (0.5 times) the value -- of a one in the next position then the result should be rounded up (away from zero). -- Otherwise the discarded digits are ignored. -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_unnecessary: INTEGER_32 = 7 -- Rounding mode to assert that no rounding is necessary; -- Rounding (potential loss of information) is not permitted. -- If any of the discarded digits are non-zero then an 'ArithmeticException'should be thrown. -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Round_up: INTEGER_32 = 0 -- Rounding mode to round away from zero; -- If any of the discarded digits are non-zero then the result will be rounded up (away from zero). -- (from MA_DECIMAL_CONTEXT_CONSTANTS) feature {NONE} -- Constants: signals Signal_division_by_zero: INTEGER_32 = 1 -- Non Zero dividend is divided by zero -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_inexact: INTEGER_32 = 2 -- A result is not exact, or overflows or underflows without being trapped -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_invalid_operation: INTEGER_32 = 3 -- A result would be undefined or impossible -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_lost_digits: INTEGER_32 = 4 -- Non-zero digits have been discarded before an operation -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_overflow: INTEGER_32 = 5 -- The exponent of a result is too large to be represented -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_rounded: INTEGER_32 = 6 -- A result has been rounded, that is, some zero or non-zero digits were discarded -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_subnormal: INTEGER_32 = 8 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Signal_underflow: INTEGER_32 = 7 -- The exponent of a result is too small to be represented -- (from MA_DECIMAL_CONTEXT_CONSTANTS) feature {NONE} -- Constants: special flags Special_infinity: INTEGER_32 = 1 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Special_none: INTEGER_32 = 0 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Special_quiet_nan: INTEGER_32 = 3 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) Special_signaling_nan: INTEGER_32 = 2 -- (from MA_DECIMAL_CONTEXT_CONSTANTS) feature {NONE} -- Constants: support Round_words: ARRAY [STRING_8] -- Textual representation of rounding modes -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := <<"Round_up", "Round_down", "Round_ceiling", "Round_floor", "Round_half_up", "Round_half_down", "Round_half_even", "Round_unnecessary">> ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class round_word_not_void: Result /= Void no_void_round_words: not Any_array_.has (Result, Void) end Rounds: ARRAY [INTEGER_32] -- Rounding modes -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := <<Round_half_up, Round_unnecessary, Round_ceiling, Round_down, Round_floor, Round_half_down, Round_half_even, Round_up>> ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class rounds_not_void: Result /= Void end Signal_words: ARRAY [STRING_8] -- Textual representation of signals -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := <<"division_by_zero", "inexact", "invalid_operation", "lost_digits", "overflow", "rounded", "underflow", "subnormal">> ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class signal_words_not_void: Result /= Void no_void_signal_words: not Any_array_.has (Result, Void) end Signals: ARRAY [INTEGER_32] -- Signals -- (from MA_DECIMAL_CONTEXT_CONSTANTS) once Result := <<Signal_division_by_zero, Signal_inexact, Signal_invalid_operation, Signal_lost_digits, Signal_overflow, Signal_rounded, Signal_underflow, Signal_subnormal>> ensure -- from MA_DECIMAL_CONTEXT_CONSTANTS instance_free: class signals_not_void: Result /= Void end feature -- Output Io: STD_FILES -- Handle to standard file setup -- (from ANY) once create Result Result.set_output_default ensure -- from ANY instance_free: class io_not_void: Result /= Void end print (o: detachable ANY) -- Write terse external representation of o -- on standard output. -- (from ANY) do if o /= Void then Io.put_string (o.out) end ensure -- from ANY instance_free: class end frozen tagged_out: STRING_8 -- New string containing terse printable representation -- of current object -- (from ANY) external "built_in" ensure -- from ANY tagged_out_not_void: Result /= Void end feature -- Platform Operating_environment: OPERATING_ENVIRONMENT -- Objects available from the operating system -- (from ANY) once create Result ensure -- from ANY instance_free: class operating_environment_not_void: Result /= Void end feature {NONE} -- Retrieval frozen internal_correct_mismatch -- Called from runtime to perform a proper dynamic dispatch on correct_mismatch -- from MISMATCH_CORRECTOR. -- (from ANY) local l_msg: STRING_8 l_exc: EXCEPTIONS do if attached {MISMATCH_CORRECTOR} Current as l_corrector then l_corrector.correct_mismatch else create l_msg.make_from_string ("Mismatch: ") create l_exc l_msg.append (generating_type.name) l_exc.raise_retrieval_exception (l_msg) end end feature -- Setting set_shared_decimal_context (new_context: MA_DECIMAL_CONTEXT) -- Set shared_decimal_context to new_context. -- It is best practice to call this routine once and for all -- at the beginning of the application to avoid unexpected -- behaviors. -- (from MA_SHARED_DECIMAL_CONTEXT) require -- from MA_SHARED_DECIMAL_CONTEXT new_context_not_void: new_context /= Void do Cell.put (new_context) ensure -- from MA_SHARED_DECIMAL_CONTEXT instance_free: class context_set: shared_decimal_context = new_context end invariant special_values: special >= Special_none and then special <= Special_quiet_nan coefficient_not_void: coefficient /= Void special_share_coefficient: is_special implies coefficient = Special_coefficient special_has_exponent_zero: is_special implies exponent = 0 special_coefficient_is_zero: Special_coefficient.is_zero -- from ANY reflexive_equality: standard_is_equal (Current) reflexive_conformance: conforms_to (Current) end -- class MA_DECIMAL
Generated by ISE EiffelStudio