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