note
	description: "[
				An arbitrary precision library for Rational numbers.
		
				Creation
					make,
					make_from_ints,
					make_from_string,
					make_from_real32,
					make_from_real64,
		
				Queries
					absolute: RATIONAL
					add (other: RATIONAL): RATIONAL
					as_real32: REAL_32
					as_real64: REAL_64
					divide alias "//" (other: RATIONAL): RATIONAL
					is_equal (other: RATIONAL): BOOLEAN
					is_greater alias ">" (other: RATIONAL): BOOLEAN
					is_greater_equal alias ">=" (other: RATIONAL): BOOLEAN
					is_less alias "<" (other: RATIONAL): BOOLEAN
					is_less_equal alias "<=" (other: RATIONAL): BOOLEAN
					is_valid_real_32: BOOLEAN
					is_valid_real_64: BOOLEAN
					max (other: [like Current] RATIONAL): RATIONAL
					min (other: [like Current] RATIONAL): RATIONAL
					minus alias "-" (other: RATIONAL): RATIONAL
					multiply (other: RATIONAL): RATIONAL
					negate: RATIONAL
					opposite alias "-": RATIONAL
					out: STRING_8
					plus alias "+" (other: RATIONAL): RATIONAL
					power alias "^" (other: INTEGER): RATIONAL
					product alias "*" (other: RATIONAL): RATIONAL
					quotient alias "/" (other: RATIONAL): RATIONAL
					reciprocal: RATIONAL
					round_to (digits: INTEGER): STRING
					square: RATIONAL
					string_is_float (s: STRING): BOOLEAN
					string_is_fraction (s: STRING): BOOLEAN
					string_is_rational (s: STRING): BOOLEAN
					subtract (other: RATIONAL): RATIONAL
		
				Commands
					canonicalize
	]"
	author: "JSO and AB"
	date: "$Date$"
	revision: "$Revision$"

class 
	RATIONAL

create 
	make,
	make_from_ints,
	make_from_string,
	make_from_real32,
	make_from_real64,
	default_create

convert
	make_from_string ({STRING_8}),
	make_from_real32 ({REAL_32}),
	make_from_real64 ({REAL_64}),
	as_real32: {REAL_32},
	as_real64: {REAL_64},
	out: {STRING_8}

feature -- Access

	generating_type: TYPE [detachable RATIONAL]
			-- 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
	
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: RATIONAL): 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_greater alias ">" (other: RATIONAL): BOOLEAN
			-- Is current object greater than other?
			-- (from COMPARABLE)
		require -- from PART_COMPARABLE
			other_exists: other /= Void
		do
			Result := other < Current
		ensure then -- from COMPARABLE
			definition: Result = (other < Current)
		end

	is_greater_equal alias ">=" (other: RATIONAL): BOOLEAN
			-- Is current object greater than or equal to other?
			-- (from COMPARABLE)
		require -- from PART_COMPARABLE
			other_exists: other /= Void
		do
			Result := not (Current < other)
		ensure then -- from COMPARABLE
			definition: Result = (other <= Current)
		end

	is_less_equal alias "<=" (other: RATIONAL): BOOLEAN
			-- Is current object less than or equal to other?
			-- (from COMPARABLE)
		require -- from PART_COMPARABLE
			other_exists: other /= Void
		do
			Result := not (other < Current)
		ensure then -- from COMPARABLE
			definition: Result = ((Current < other) or (Current ~ other))
		end

	max (other: RATIONAL): RATIONAL
			-- The greater of current object and other
			-- (from COMPARABLE)
		require -- from COMPARABLE
			other_exists: other /= Void
		do
			if Current >= other then
				Result := Current
			else
				Result := other
			end
		ensure -- from COMPARABLE
			current_if_not_smaller: Current >= other implies Result = Current
			other_if_smaller: Current < other implies Result = other
		end

	min (other: RATIONAL): RATIONAL
			-- The smaller of current object and other
			-- (from COMPARABLE)
		require -- from COMPARABLE
			other_exists: other /= Void
		do
			if Current <= other then
				Result := Current
			else
				Result := other
			end
		ensure -- from COMPARABLE
			current_if_not_greater: Current <= other implies Result = Current
			other_if_greater: Current > other implies Result = 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: RATIONAL): 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

	three_way_comparison (other: RATIONAL): INTEGER_32
			-- If current object equal to other, 0;
			-- if smaller, -1; if greater, 1
			-- (from COMPARABLE)
		require -- from COMPARABLE
			other_exists: other /= Void
		do
			if Current < other then
				Result := -1
			elseif other < Current then
				Result := 1
			end
		ensure -- from COMPARABLE
			equal_zero: (Result = 0) = (Current ~ other)
			smaller_negative: (Result = -1) = (Current < other)
			greater_positive: (Result = 1) = (Current > other)
		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

	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 -- 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: RATIONAL)
			-- Update current object using fields of object attached
			-- to other, so as to yield equal objects.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		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: RATIONAL)
			-- 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: RATIONAL
			-- 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: RATIONAL)
			-- 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: RATIONAL
			-- 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: RATIONAL
			-- 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

	frozen as_attached: attached RATIONAL
		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

	frozen default: detachable RATIONAL
			-- 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

	frozen do_nothing
			-- Execute a null action.
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end
	
feature -- Commands

	canonicalize
			-- Canonicalize the current rational by dividing its numerator
			-- and denominator by their GCD.
		local
			g: BIG_INTEGER
		do
			g := p.gcd (q)
			p := p.divide (g)
			q := q.divide (g)
		end
	
feature {NONE} -- Constructors

	default_create
			-- Process instances of classes with no creation clause.
			-- (Default: do nothing.)
		do
			p := create {BIG_INTEGER}.make_from_string ("1")
			q := create {BIG_INTEGER}.make_from_string ("1")
		end

	make (a_p, a_q: INTEGER_64)
			-- Initialization for Current.
		require
			q_non_zero: a_q /= 0
		do
			create p.make_from_integer64 (a_p)
			create q.make_from_integer64 (a_q)
			canonicalize
		end

	make_from_ints (a_p, a_q: BIG_INTEGER)
			-- Create by specifying the pand q values
		require
			q_non_zero: a_q /~ a_q.zero
		do
			p := a_p
			q := a_q
			canonicalize
		end

	make_from_real32 (r: REAL_32)
			-- Create from a REAL_32, r
		do
			make_from_string (r.out)
		end

	make_from_real64 (r: REAL_64)
			-- Create from a REAL_64
		do
			make_from_string (r.out)
		end

	make_from_string (s: STRING_8)
			-- Create from string s
		require
			has_correct_format: string_is_rational (s)
		local
			p_q: like get_p_q
			i: INTEGER_32
			p_, q_: STRING_8
		do
			if string_is_fraction (s) then
				p_q := get_p_q (s)
				make_from_ints (create {BIG_INTEGER}.make_from_string (p_q.a_p), create {BIG_INTEGER}.make_from_string (p_q.a_q))
			else
				check
						string_is_float (s)
				end
				i := s.index_of ('.', 1)
				create p_.make_from_string (s)
				p_.remove (i)
				check
						p_.index_of ('.', 1) = 0
				end
				q_ := "1"
				across
					1 |..| (s.count - i) as i_
				loop
					q_.append_character ('0')
				end
				make_from_ints (create {BIG_INTEGER}.make_from_string (p_), create {BIG_INTEGER}.make_from_string (q_))
			end
		end
	
feature {RATIONAL} -- Internal attributes

	p: BIG_INTEGER
			-- Numerator and Denominator

	q: BIG_INTEGER
			-- Numerator and Denominator
	
feature -- Internal queries

	get_p_q (s: STRING_8): TUPLE [a_p: like s; a_q: like s]
			-- Returns the numerator and denominator parsed from s.
		require
				string_is_rational (s)
		local
			i: INTEGER_32
		do
			i := s.index_of ('/', 1)
			create Result
			if i > 0 then
				Result.a_p := s.substring (1, i - 1)
				Result.a_q := s.substring (i + 1, s.count)
			else
				Result.a_p := s
				Result.a_q := "1"
			end
		end
	
feature -- Operations

	abs: like Current
			-- Absolute value of Current
			-- Was declared in RATIONAL as synonym of absolute.
		do
			if Current >= zero then
				Result := identity
			else
				Result := opposite
			end
		end

	absolute: like Current
			-- Absolute value of Current
			-- Was declared in RATIONAL as synonym of abs.
		do
			if Current >= zero then
				Result := identity
			else
				Result := opposite
			end
		end

	add (other: like Current): like Current
			-- Return the result of adding Current to other
			-- Was declared in RATIONAL as synonym of plus.
		do
			create Result.make_from_ints ((p * other.q) + (q * other.p), q * other.q)
		end

	divide alias "//" (other: like Current): like Current
			-- Return the result of dividing Curent by other
			-- Was declared in RATIONAL as synonym of quotient.
		require
			denominator_non_zero: other /~ zero
		do
			Result := Current * other.reciprocal
		end

	exp (other: INTEGER_32): RATIONAL
			-- Return the value of Current raised to the power other
			-- Was declared in RATIONAL as synonym of power.
		do
			if other = 0 then
				Result := one
			else
				Result := Current
				across
					1 |..| (other.abs - 1) as i
				loop
					Result := Result * Current
				end
				if other < 0 then
					Result := Result.reciprocal
				end
			end
		end

	minus alias "-" (other: like Current): like Current
			-- Return the result of subtracting other from Current
			-- Was declared in RATIONAL as synonym of subtract.
		do
			Result := Current + (- other)
		end

	multiply (other: like Current): like Current
			-- Return the result of multiplying Current by other
			-- Was declared in RATIONAL as synonym of product.
		do
			create Result.make_from_ints (p * other.p, q * other.q)
		end

	negate: like Current
			-- Negate Current
			-- Was declared in RATIONAL as synonym of opposite.
		do
			create Result.make_from_ints (- p, q)
		end

	opposite alias "-": like Current
			-- Negate Current
			-- Was declared in RATIONAL as synonym of negate.
		do
			create Result.make_from_ints (- p, q)
		end

	plus alias "+" (other: like Current): like Current
			-- Return the result of adding Current to other
			-- Was declared in RATIONAL as synonym of add.
		do
			create Result.make_from_ints ((p * other.q) + (q * other.p), q * other.q)
		end

	power alias "^" (other: INTEGER_32): RATIONAL
			-- Return the value of Current raised to the power other
			-- Was declared in RATIONAL as synonym of exp.
		do
			if other = 0 then
				Result := one
			else
				Result := Current
				across
					1 |..| (other.abs - 1) as i
				loop
					Result := Result * Current
				end
				if other < 0 then
					Result := Result.reciprocal
				end
			end
		end

	product alias "*" (other: like Current): like Current
			-- Return the result of multiplying Current by other
			-- Was declared in RATIONAL as synonym of multiply.
		do
			create Result.make_from_ints (p * other.p, q * other.q)
		end

	quotient alias "/" (other: like Current): like Current
			-- Return the result of dividing Curent by other
			-- Was declared in RATIONAL as synonym of divide.
		require
			denominator_non_zero: other /~ zero
		do
			Result := Current * other.reciprocal
		end

	reciprocal: like Current
			-- Return 1 / Current
		do
			create Result.make_from_ints (q, p)
		end

	square: RATIONAL
			-- Return the value of Current * Current
		do
			Result := Current * Current
		end

	subtract (other: like Current): like Current
			-- Return the result of subtracting other from Current
			-- Was declared in RATIONAL as synonym of minus.
		do
			Result := Current + (- other)
		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 -- Queries

	as_real32: REAL_32
			-- Represent Current as a REAL_32
		require
				is_valid_real_32
		do
			Result := p.real_division (q).precise_out.to_real_32
		end

	as_real64: REAL_64
			-- Represent Current as a REAL_64
		require
				is_valid_real_64
		do
			Result := p.real_division (q).precise_out.to_real_64
		end

	debug_output: STRING_8
			-- Debut output for Current
		do
			Result := out
		ensure -- from DEBUG_OUTPUT
			result_not_void: Result /= Void
		end

	divisible (other: like Current): BOOLEAN
			-- May current object be divided by other?
		do
			Result := other /~ zero
		end

	exponentiable (other: NUMERIC): BOOLEAN
			-- May current object be elevated to the power other?
		do
			Result := False
		end

	identity alias "+": like Current
			-- Unary plus
		do
			create Result.make_from_ints (p, q)
		end

	int_zero: BIG_INTEGER
			-- Returns an Integer with value 0 for creation
		do
			Result := create {attached BIG_INTEGER}.make_from_string ("0")
		end

	is_canonical: BOOLEAN
			-- Is Current in canonical form?
		do
			Result := p.gcd (q) ~ p.one
		end

	is_equal (other: like Current): BOOLEAN
			-- Is other value equal to current
		require -- from ANY
			other_not_void: other /= Void
		do
			Result := p * other.q ~ q * other.p
		ensure -- from ANY
			symmetric: Result implies other ~ Current
			consistent: standard_is_equal (other) implies Result
		ensure then -- from COMPARABLE
			trichotomy: Result = (not (Current < other) and not (other < Current))
		end

	is_less alias "<" (other: like Current): BOOLEAN
			-- Is current object less than other?
		require -- from PART_COMPARABLE
			other_exists: other /= Void
		do
			if Current ~ create {attached RATIONAL}.make_from_string ("0") then
				Result := Current.p < other.p * other.q
			elseif other ~ create {attached RATIONAL}.make_from_string ("0") then
				Result := Current.p * Current.q < other.p
			else
				Result := p * other.q < q * other.p
			end
		ensure then -- from COMPARABLE
			asymmetric: Result implies not (other < Current)
		end

	is_valid_real_32: BOOLEAN
			-- Is Current a valid REAL_32?
		do
			Result := p.out.is_integer_32 and then q.out.is_integer_32 and then p.real_division (q).out.is_real_32
		end

	is_valid_real_64: BOOLEAN
			-- Is Current a valid REAL_64?
		do
			Result := p.out.is_integer_64 and then q.out.is_integer_64 and then p.real_division (q).out.is_real_64
		end

	one: like Current
			-- Neutral element for "*" and "/"
		do
			create Result.make (1, 1)
		end

	out: STRING_8
			-- Return a string representation of Current
		do
			if q ~ q.one then
				Result := p.out
			else
				Result := p.out + "/" + q.out
			end
		ensure -- from ANY
			out_not_void: Result /= Void
		end

	string_is_float (s: STRING_8): BOOLEAN
			-- Does s represent a valid and well-defined decimal number
			-- with potentially a floating point? This function was copied
			-- from {INT}.ensureValid, which came from mathmodels' VALUE.
		require
			non_void: s /= Void
			non_empty: not s.is_empty
		local
			seendot: BOOLEAN
			i: INTEGER_32
		do
			seendot := False
			Result := True
			from
				i := 1
			until
				i > s.count
			loop
				if s.item (i) = '-' then
					if i > 1 then
						Result := False
						i := s.count + 1
					end
				elseif s.item (i) = '.' then
					if i = s.count or seendot then
						Result := False
						i := s.count + 1
					end
					seendot := True
				elseif not s.item (i).is_digit then
					Result := False
					i := s.count + 1
				end
				i := i + 1
			end
		end

	string_is_fraction (s: STRING_8): BOOLEAN
			-- Does s represent a valid and well-defined fraction?
			-- It must contain at most one '/', which separates the numerator
			-- from the denominator (no whitespace allowed). Also, either
			-- the numerator or denominator must be non-zero. Further, if '/'
			-- is present, what comes before and after it must be valid INTs.
			-- If s doesn't contain a '/', a denominator of 1 is assumed.
		local
			i: INTEGER_32
			p_s, q_s: STRING_8
			i1, i2: BIG_INTEGER
		do
			i := s.index_of ('/', 1)
			i1 := create {attached BIG_INTEGER}.make_from_string ("0")
			if i > 0 then
				if s.last_index_of ('/', s.count) = i and then s.count >= 3 then
					p_s := s.substring (1, i - 1)
					q_s := s.substring (i + 1, s.count)
					if p_s.count > 0 and q_s.count > 0 then
						if i1.is_string_int (p_s) and i1.is_string_int (q_s) then
							i1 := create {attached BIG_INTEGER}.make_from_string (p_s)
							i2 := create {attached BIG_INTEGER}.make_from_string (q_s)
							Result := not (i1 ~ i1.zero and i2 ~ i2.zero)
						end
					else
						Result := False
					end
				end
			else
				Result := (not s.is_empty) and then i1.is_string_int (s)
			end
			if i2 ~ int_zero then
				Result := False
			end
		end

	string_is_rational (s: STRING_8): BOOLEAN
			-- Does s represent a fraction or a decimal with a floating
			-- point?
		do
			Result := string_is_fraction (s) or else string_is_float (s)
		end

	zero: like Current
			-- Neutral element for "+" and "-"
		do
			create Result.make (0, 1)
		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 -- rounding

	round_to (digits: INTEGER_32): STRING_8
			-- Round Current to digits number of digits. Uses half-up rounding.
		local
			d: DECIMAL
		do
			d := p.real_division (q)
			Result := d.round_to (digits).precise_out
		end
	
invariant
	well_defined: q /~ q.zero

		-- from ANY
	reflexive_equality: standard_is_equal (Current)
	reflexive_conformance: conforms_to (Current)

		-- from COMPARABLE
	irreflexive_comparison: not (Current < Current)

end -- class RATIONAL

Generated by ISE EiffelStudio