note
	description: "[
		Perform arithmetic (+, -, *, /) on real numbers of arbitrary precision.
		In the case of division, the default precision is 35 digits after
		the decimal point. This can be changed via set_division_precision.
		The queries is_integer, is_natural and is_natural1 may be used to
		check that the value is an integer or natural number. 
		out provides a string represesentation rounded to two decimal places, and 
		precise_out is a string representation of the precise value. The corresponding
		C# class was the inspiration for this class.
	]"
	author: "Vlad Gerchikov for the Software Engineering Lab at sel@cse.yorku.ca"
	date: "$April 15, 2008$"
	revision: "$1.0$"

expanded class 
	VALUE

create 
	make_from_string,
	make,
	make_from_int,
	default_create

convert
	make_from_string ({STRING_8}),
	as_double: {REAL_64}

feature -- Access

	generating_type: TYPE [detachable VALUE]
			-- 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: VALUE): 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: VALUE): 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: VALUE): 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: VALUE): 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: VALUE): VALUE
			-- 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: VALUE): VALUE
			-- 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: VALUE): 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: VALUE): 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 -- Conversion

	as_double: REAL_64
			-- represent as a DOUBLE
		do
			Result := precise_out.to_double
		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: VALUE)
			-- 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: VALUE)
			-- 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: VALUE
			-- 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: VALUE)
			-- 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: VALUE
			-- 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: VALUE
			-- 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 VALUE
		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 VALUE
			-- 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 -- 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 -- comparison

	is_equal (other: VALUE): BOOLEAN
			-- check whether other is equal to current or not
		require -- from ANY
			other_not_void: other /= Void
		local
			r1i, r2i, d1, d2: INTEGER_32
			r1, r2: VALUE
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			r1.aligndecimal (r2)
			r1.alignwhole (r2)
			Result := True
			from
				r1i := 1
				r2i := 1
			until
				r1i > r1.s_.count or r2i > r2.s_.count
			loop
				d1 := todigit (r1.s_.item (r1i))
				d2 := todigit (r2.s_.item (r2i))
				if d1 /= d2 then
					Result := False
					r1i := r1.s_.count + 1
				end
				r1i := r1i + 1
				r2i := r2i + 1
			end
		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: VALUE): BOOLEAN
			-- whether current is less than other
		require -- from PART_COMPARABLE
			other_exists: other /= Void
		local
			r1i, r2i, d1, d2: INTEGER_32
			r1, r2: VALUE
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				Result := True
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				Result := False
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				r1.negate
				r2.negate
				Result := r2 < r1
			else
				r1.aligndecimal (r2)
				r1.alignwhole (r2)
				Result := False
				from
					r1i := 1
					r2i := 1
				until
					r1i > r1.s_.count or r2i > r2.s_.count
				loop
					d1 := todigit (r1.s_.item (r1i))
					d2 := todigit (r2.s_.item (r2i))
					if d1 < d2 then
						Result := True
						r1i := r1.s_.count + 1
					elseif d1 > d2 then
						Result := False
						r1i := r1.s_.count + 1
					end
					r1i := r1i + 1
					r2i := r2i + 1
				end
			end
		ensure then -- from COMPARABLE
			asymmetric: Result implies not (other < Current)
		end
	
feature {NONE} -- constructors

	default_create
			-- create an empty MONEY_VALUE object (it's equivalent to 0)
		require -- from  ANY
			True
		local
			empty: STRING_8
		do
			divisiondecimalprecision_ := Default_precision
			empty := "0"
			s_ := empty.twin
		ensure then
				s_.is_equal ("0")
		end

	make_from_int (int: INTEGER_32)
			-- create a MONEY_VALUE object from integer m
		local
			ch: CHARACTER_8
			m, n, d: INTEGER_32
			neg: BOOLEAN
		do
			divisiondecimalprecision_ := Default_precision
			m := int
			if m = 0 then
				create s_.make_from_string ("0")
			else
				neg := m < 0
				if neg then
					m := m * -1
				end
				from
					n := m
					create s_.make_empty
				until
					n = 0
				loop
					d := n \\ 10
					n := n // 10
					ch := tochar (d)
					s_.insert_character (ch, 1)
				end
				if neg then
					negate
				end
				normalize
			end
		end

	make_from_string (s: STRING_8)
			-- create a MONEY_VALUE object from string s
		require
			non_void: s /= Void
			non_empty: not s.is_empty
			has_correct_format: ensurevalid (s)
		do
			divisiondecimalprecision_ := Default_precision
			s_ := s.twin
			normalize
		end
	
feature -- operations

	add (other: VALUE): VALUE
			-- adds current to other and returns a new object
			-- Was declared in VALUE as synonym of plus.
		local
			res, empty: STRING_8
			carry, r1i, r2i, d1, d2, d: INTEGER_32
			ch: CHARACTER_8
			r1, r2: VALUE
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r2 - r1).clone_me
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 - r2).clone_me
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r1.negate
				r2.negate
				Result := (r1 + r2).clone_me
				Result.negate
			else
				r1.aligndecimal (r2)
				r1.alignwhole (r2)
				empty := ""
				res := empty.twin
				from
					r1i := r1.s_.count
					r2i := r2.s_.count
				until
					r1i < 1 or r2i < 1
				loop
					ch := '0'
					if r1.s_.item (r1i) /= '.' and r2.s_.item (r2i) /= '.' then
						d1 := todigit (r1.s_.item (r1i))
						d2 := todigit (r2.s_.item (r2i))
						d := carry + d1 + d2
						if d >= 10 then
							carry := d // 10
							d := d - 10
						else
							carry := 0
						end
						ch := tochar (d)
					elseif r1.s_.item (r1i) = '.' and r2.s_.item (r2i) = '.' then
						ch := '.'
					end
					res.insert_character (ch, 1)
					r1i := r1i - 1
					r2i := r2i - 1
				end
				if carry > 0 then
					res.insert_character (tochar (carry), 1)
				end
				create Result.make_from_string (res)
			end
		end

	divide (other: VALUE): VALUE
			-- divides current by other and returns a new object
			-- Was declared in VALUE as synonym of quotient.
		local
			r1, r2, tr, diff, x, sum, prod: VALUE
			r1dotpos, r2dotpos, r1precision, r2precision, r1numtrailingzeros, r2numtrailingzeros, scalefactor, i, startpos, r1i, d: INTEGER_32
			s, res, empty: STRING_8
			pad: detachable STRING_8
			stoploop: BOOLEAN
			ch: CHARACTER_8
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.is_equal (zero) then
				Result := zero
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r1 / r2).clone_me
				Result.negate
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 / r2).clone_me
				Result.negate
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r1.negate
				r2.negate
				Result := (r1 / r2).clone_me
			else
				r1dotpos := r1.s_.index_of ('.', 1)
				r2dotpos := r2.s_.index_of ('.', 1)
				r1precision := 0
				r2precision := 0
				if r1dotpos > 0 then
					r1precision := r1.s_.count - r1dotpos
					r1.s_.remove (r1dotpos)
					r1.normalize
				end
				if r2dotpos > 0 then
					r2precision := r2.s_.count - r2dotpos
					r2.s_.remove (r2dotpos)
					r2.normalize
				end
				pad := Void
				if r1precision > r2precision then
					pad := r2.s_
				elseif r2precision > r1precision then
					pad := r1.s_
				end
				if pad /= Void then
					create s.make_filled ('0', (r1precision - r2precision).abs)
					pad.append (s)
				end
				r1numtrailingzeros := 0
				r2numtrailingzeros := 0
				scalefactor := 0
				from
					i := r1.s_.count
				until
					i < 1
				loop
					if r1.s_.item (i) = '0' then
						r1numtrailingzeros := r1numtrailingzeros + 1
					else
						i := 0
					end
					i := i - 1
				end
				from
					i := r2.s_.count
				until
					i < 1
				loop
					if r2.s_.item (i) = '0' then
						r2numtrailingzeros := r2numtrailingzeros + 1
					else
						i := 0
					end
					i := i - 1
				end
				if r1numtrailingzeros < r2numtrailingzeros then
					create s.make_filled ('0', r2numtrailingzeros - r1numtrailingzeros)
					r1.s_.append (s)
					scalefactor := scalefactor + r2numtrailingzeros - r1numtrailingzeros
					r1numtrailingzeros := r2numtrailingzeros
				end
				if r1numtrailingzeros - r2numtrailingzeros < divisiondecimalprecision_ + 1 then
					scalefactor := scalefactor + divisiondecimalprecision_ + 1 - (r1numtrailingzeros - r2numtrailingzeros)
					create s.make_filled ('0', divisiondecimalprecision_ + 1 - (r1numtrailingzeros - r2numtrailingzeros))
					r1.s_.append (s)
				end
				if r1 < r2 then
					scalefactor := scalefactor + r2.s_.count - r1.s_.count + 1
					create s.make_filled ('0', r2.s_.count - r1.s_.count + 1)
					r1.s_.append (s)
				end
				if r1.s_.count - r2.s_.count < divisiondecimalprecision_ then
					scalefactor := scalefactor + divisiondecimalprecision_ - (r1.s_.count - r2.s_.count)
					create s.make_filled ('0', divisiondecimalprecision_ - (r1.s_.count - r2.s_.count))
					r1.s_.append (s)
				end
				startpos := r2.s_.count + 1
				if r1.s_.count > r2.s_.count then
					from
						stoploop := False
					until
						startpos > r1.s_.count or stoploop
					loop
						s := r1.s_.substring (1, startpos - 1)
						create tr.make_from_string (s)
						if tr >= r2 then
							stoploop := True
						else
							startpos := startpos + 1
						end
					end
				end
				empty := ""
				res := empty.twin
				create diff
				from
					r1i := startpos - 1
				until
					r1i > r1.s_.count
				loop
					if r1i = startpos - 1 then
						create x.make_from_string (r1.s_.substring (1, r1i))
					else
						diff.s_.insert_character (r1.s_.item (r1i), diff.s_.count + 1)
						create x
						x := diff.clone_me
					end
					d := 0
					create sum
					from
						stoploop := False
					until
						stoploop
					loop
						sum := sum + r2
						if sum > x then
							stoploop := True
						else
							d := d + 1
						end
					end
					ch := tochar (d)
					res.insert_character (ch, res.count + 1)
					create prod
					create s.make_filled (ch, 1)
					create tr.make_from_string (s)
					prod := tr * r2
					diff := x - prod
					r1i := r1i + 1
				end
				if scalefactor > 0 then
					if scalefactor > res.count then
						create s.make_filled ('0', scalefactor - res.count)
						res.insert_string (s, 1)
					end
					res.insert_character ('.', res.count - scalefactor + 1)
				end
				create Result.make_from_string (res)
			end
		end

	divisible (other: VALUE): BOOLEAN
			-- may current object be divided by other?
		require -- from NUMERIC
			other_exists: other /= Void
		do
			Result := not other.is_equal (zero)
		end

	exponentiable (other: NUMERIC): BOOLEAN
			-- may current object be elevated to the power other?
		require -- from NUMERIC
			other_exists: other /= Void
		do
			Result := False
		end

	identity alias "+": VALUE
			-- unary plus
		do
			create Result.make_from_string (s_)
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end

	is_integer: BOOLEAN
		do
			Result := s_.index_of ('.', 1) = 0
		end

	is_natural: BOOLEAN
		do
			Result := is_integer and Current >= zero
		end

	is_natural1: BOOLEAN
		do
			Result := is_integer and Current >= one
		end

	minus alias "-" (other: VALUE): VALUE
			-- subtracts other from current and returns a new object
			-- Was declared in VALUE as synonym of subtract.
		require -- from NUMERIC
			other_exists: other /= Void
		local
			res, empty: STRING_8
			r1, r2: VALUE
			r1i, r2i, d1, d2, dp, i, j: INTEGER_32
			ch: CHARACTER_8
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r1 + r2).clone_me
				Result.negate
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 + r2).clone_me
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 + r2).clone_me
			else
				if r1 < r2 then
					Result := (r2 - r1).clone_me
					Result.negate
				else
					r1.aligndecimal (r2)
					r1.alignwhole (r2)
					empty := ""
					res := empty.twin
					from
						r1i := r1.s_.count
						r2i := r2.s_.count
					until
						r1i < 1 or r2i < 1
					loop
						ch := '0'
						if r1.s_.item (r1i) /= '.' and r2.s_.item (r2i) /= '.' then
							d1 := todigit (r1.s_.item (r1i))
							d2 := todigit (r2.s_.item (r2i))
							if d1 < d2 then
								from
									i := r1i - 1
								until
									i < 1
								loop
									if r1.s_.item (i) /= '.' then
										dp := todigit (r1.s_.item (i))
										if dp > 0 then
											r1.s_.put (tochar (dp - 1), i)
											from
												j := i + 1
											until
												j > r1i - 1
											loop
												if r1.s_.item (j) /= '.' then
													r1.s_.put (tochar (todigit (r1.s_.item (j)) + 9), j)
												end
												j := j + 1
											end
											d1 := d1 + 10
											i := 0
										end
									end
									i := i - 1
								end
							end
							ch := tochar (d1 - d2)
						elseif r1.s_.item (r1i) = '.' and r2.s_.item (r2i) = '.' then
							ch := '.'
						end
						res.insert_character (ch, 1)
						r1i := r1i - 1
						r2i := r2i - 1
					end
					create Result.make_from_string (res)
				end
			end
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end

	multiply (other: VALUE): VALUE
			-- multiplies current by other and returns a new object
			-- Was declared in VALUE as synonym of product.
		local
			r1, r2, tr1, tr2, tr: VALUE
			r1dotpos, r2dotpos, precision, r1i, r2i, carry, d1, d2, d, diff, i: INTEGER_32
			res, cres, tmp, empty: STRING_8
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r1 * r2).clone_me
				Result.negate
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 * r2).clone_me
				Result.negate
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r1.negate
				r2.negate
				Result := (r1 * r2).clone_me
			else
				r1dotpos := r1.s_.index_of ('.', 1)
				r2dotpos := r2.s_.index_of ('.', 1)
				precision := 0
				if r1dotpos > 0 then
					precision := precision + r1.s_.count - r1dotpos
					r1.s_.remove (r1dotpos)
				end
				if r2dotpos > 0 then
					precision := precision + r2.s_.count - r2dotpos
					r2.s_.remove (r2dotpos)
				end
				empty := ""
				res := empty.twin
				from
					r2i := r2.s_.count
				until
					r2i < 1
				loop
					cres := empty.twin
					carry := 0
					from
						r1i := r1.s_.count
					until
						r1i < 1
					loop
						d1 := todigit (r1.s_.item (r1i))
						d2 := todigit (r2.s_.item (r2i))
						d := carry + d1 * d2
						if d >= 10 then
							carry := d // 10
							d := d \\ 10
						else
							carry := 0
						end
						cres.insert_character (tochar (d), 1)
						r1i := r1i - 1
					end
					if carry > 0 then
						cres.insert_character (tochar (carry), 1)
					end
					if res.count = 0 then
						res := cres.twin
					else
						create tmp.make_filled ('0', r2.s_.count - r2i)
						cres.append (tmp)
						create tr1.make_from_string (cres)
						create tr2.make_from_string (res)
						tr := tr1 + tr2
						res := tr.s_.twin
					end
					r2i := r2i - 1
				end
				if precision > 0 then
					if precision > res.count then
						diff := precision - res.count
						from
							i := 1
						until
							i > diff
						loop
							res.insert_character ('0', 1)
							i := i + 1
						end
					end
					res.insert_character ('.', res.count - precision + 1)
				end
				create Result.make_from_string (res)
			end
		end

	one: VALUE
			-- neutral element for "*" and "/"
		do
			create Result.make_from_string ("1")
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end

	opposite alias "-": VALUE
			-- unary minus
		do
			create Result.make_from_string (s_)
			Result.negate
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end

	plus alias "+" (other: VALUE): VALUE
			-- adds current to other and returns a new object
			-- Was declared in VALUE as synonym of add.
		require -- from NUMERIC
			other_exists: other /= Void
		local
			res, empty: STRING_8
			carry, r1i, r2i, d1, d2, d: INTEGER_32
			ch: CHARACTER_8
			r1, r2: VALUE
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r2 - r1).clone_me
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 - r2).clone_me
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r1.negate
				r2.negate
				Result := (r1 + r2).clone_me
				Result.negate
			else
				r1.aligndecimal (r2)
				r1.alignwhole (r2)
				empty := ""
				res := empty.twin
				from
					r1i := r1.s_.count
					r2i := r2.s_.count
				until
					r1i < 1 or r2i < 1
				loop
					ch := '0'
					if r1.s_.item (r1i) /= '.' and r2.s_.item (r2i) /= '.' then
						d1 := todigit (r1.s_.item (r1i))
						d2 := todigit (r2.s_.item (r2i))
						d := carry + d1 + d2
						if d >= 10 then
							carry := d // 10
							d := d - 10
						else
							carry := 0
						end
						ch := tochar (d)
					elseif r1.s_.item (r1i) = '.' and r2.s_.item (r2i) = '.' then
						ch := '.'
					end
					res.insert_character (ch, 1)
					r1i := r1i - 1
					r2i := r2i - 1
				end
				if carry > 0 then
					res.insert_character (tochar (carry), 1)
				end
				create Result.make_from_string (res)
			end
		ensure -- from NUMERIC
			result_exists: Result /= Void
			commutative: Result ~ (other + Current)
		end

	product alias "*" (other: VALUE): VALUE
			-- multiplies current by other and returns a new object
			-- Was declared in VALUE as synonym of multiply.
		require -- from NUMERIC
			other_exists: other /= Void
		local
			r1, r2, tr1, tr2, tr: VALUE
			r1dotpos, r2dotpos, precision, r1i, r2i, carry, d1, d2, d, diff, i: INTEGER_32
			res, cres, tmp, empty: STRING_8
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r1 * r2).clone_me
				Result.negate
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 * r2).clone_me
				Result.negate
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r1.negate
				r2.negate
				Result := (r1 * r2).clone_me
			else
				r1dotpos := r1.s_.index_of ('.', 1)
				r2dotpos := r2.s_.index_of ('.', 1)
				precision := 0
				if r1dotpos > 0 then
					precision := precision + r1.s_.count - r1dotpos
					r1.s_.remove (r1dotpos)
				end
				if r2dotpos > 0 then
					precision := precision + r2.s_.count - r2dotpos
					r2.s_.remove (r2dotpos)
				end
				empty := ""
				res := empty.twin
				from
					r2i := r2.s_.count
				until
					r2i < 1
				loop
					cres := empty.twin
					carry := 0
					from
						r1i := r1.s_.count
					until
						r1i < 1
					loop
						d1 := todigit (r1.s_.item (r1i))
						d2 := todigit (r2.s_.item (r2i))
						d := carry + d1 * d2
						if d >= 10 then
							carry := d // 10
							d := d \\ 10
						else
							carry := 0
						end
						cres.insert_character (tochar (d), 1)
						r1i := r1i - 1
					end
					if carry > 0 then
						cres.insert_character (tochar (carry), 1)
					end
					if res.count = 0 then
						res := cres.twin
					else
						create tmp.make_filled ('0', r2.s_.count - r2i)
						cres.append (tmp)
						create tr1.make_from_string (cres)
						create tr2.make_from_string (res)
						tr := tr1 + tr2
						res := tr.s_.twin
					end
					r2i := r2i - 1
				end
				if precision > 0 then
					if precision > res.count then
						diff := precision - res.count
						from
							i := 1
						until
							i > diff
						loop
							res.insert_character ('0', 1)
							i := i + 1
						end
					end
					res.insert_character ('.', res.count - precision + 1)
				end
				create Result.make_from_string (res)
			end
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end

	quotient alias "/" (other: VALUE): VALUE
			-- divides current by other and returns a new object
			-- Was declared in VALUE as synonym of divide.
		require -- from NUMERIC
			other_exists: other /= Void
			good_divisor: divisible (other)
		local
			r1, r2, tr, diff, x, sum, prod: VALUE
			r1dotpos, r2dotpos, r1precision, r2precision, r1numtrailingzeros, r2numtrailingzeros, scalefactor, i, startpos, r1i, d: INTEGER_32
			s, res, empty: STRING_8
			pad: detachable STRING_8
			stoploop: BOOLEAN
			ch: CHARACTER_8
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.is_equal (zero) then
				Result := zero
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r1 / r2).clone_me
				Result.negate
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 / r2).clone_me
				Result.negate
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r1.negate
				r2.negate
				Result := (r1 / r2).clone_me
			else
				r1dotpos := r1.s_.index_of ('.', 1)
				r2dotpos := r2.s_.index_of ('.', 1)
				r1precision := 0
				r2precision := 0
				if r1dotpos > 0 then
					r1precision := r1.s_.count - r1dotpos
					r1.s_.remove (r1dotpos)
					r1.normalize
				end
				if r2dotpos > 0 then
					r2precision := r2.s_.count - r2dotpos
					r2.s_.remove (r2dotpos)
					r2.normalize
				end
				pad := Void
				if r1precision > r2precision then
					pad := r2.s_
				elseif r2precision > r1precision then
					pad := r1.s_
				end
				if pad /= Void then
					create s.make_filled ('0', (r1precision - r2precision).abs)
					pad.append (s)
				end
				r1numtrailingzeros := 0
				r2numtrailingzeros := 0
				scalefactor := 0
				from
					i := r1.s_.count
				until
					i < 1
				loop
					if r1.s_.item (i) = '0' then
						r1numtrailingzeros := r1numtrailingzeros + 1
					else
						i := 0
					end
					i := i - 1
				end
				from
					i := r2.s_.count
				until
					i < 1
				loop
					if r2.s_.item (i) = '0' then
						r2numtrailingzeros := r2numtrailingzeros + 1
					else
						i := 0
					end
					i := i - 1
				end
				if r1numtrailingzeros < r2numtrailingzeros then
					create s.make_filled ('0', r2numtrailingzeros - r1numtrailingzeros)
					r1.s_.append (s)
					scalefactor := scalefactor + r2numtrailingzeros - r1numtrailingzeros
					r1numtrailingzeros := r2numtrailingzeros
				end
				if r1numtrailingzeros - r2numtrailingzeros < divisiondecimalprecision_ + 1 then
					scalefactor := scalefactor + divisiondecimalprecision_ + 1 - (r1numtrailingzeros - r2numtrailingzeros)
					create s.make_filled ('0', divisiondecimalprecision_ + 1 - (r1numtrailingzeros - r2numtrailingzeros))
					r1.s_.append (s)
				end
				if r1 < r2 then
					scalefactor := scalefactor + r2.s_.count - r1.s_.count + 1
					create s.make_filled ('0', r2.s_.count - r1.s_.count + 1)
					r1.s_.append (s)
				end
				if r1.s_.count - r2.s_.count < divisiondecimalprecision_ then
					scalefactor := scalefactor + divisiondecimalprecision_ - (r1.s_.count - r2.s_.count)
					create s.make_filled ('0', divisiondecimalprecision_ - (r1.s_.count - r2.s_.count))
					r1.s_.append (s)
				end
				startpos := r2.s_.count + 1
				if r1.s_.count > r2.s_.count then
					from
						stoploop := False
					until
						startpos > r1.s_.count or stoploop
					loop
						s := r1.s_.substring (1, startpos - 1)
						create tr.make_from_string (s)
						if tr >= r2 then
							stoploop := True
						else
							startpos := startpos + 1
						end
					end
				end
				empty := ""
				res := empty.twin
				create diff
				from
					r1i := startpos - 1
				until
					r1i > r1.s_.count
				loop
					if r1i = startpos - 1 then
						create x.make_from_string (r1.s_.substring (1, r1i))
					else
						diff.s_.insert_character (r1.s_.item (r1i), diff.s_.count + 1)
						create x
						x := diff.clone_me
					end
					d := 0
					create sum
					from
						stoploop := False
					until
						stoploop
					loop
						sum := sum + r2
						if sum > x then
							stoploop := True
						else
							d := d + 1
						end
					end
					ch := tochar (d)
					res.insert_character (ch, res.count + 1)
					create prod
					create s.make_filled (ch, 1)
					create tr.make_from_string (s)
					prod := tr * r2
					diff := x - prod
					r1i := r1i + 1
				end
				if scalefactor > 0 then
					if scalefactor > res.count then
						create s.make_filled ('0', scalefactor - res.count)
						res.insert_string (s, 1)
					end
					res.insert_character ('.', res.count - scalefactor + 1)
				end
				create Result.make_from_string (res)
			end
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end

	set_division_precision (i: INTEGER_32)
			-- sets divisionDecimalPrecision_ to 'i'
		require
			greater_than_zero: i > 0
		do
			divisiondecimalprecision_ := i
		end

	subtract (other: VALUE): VALUE
			-- subtracts other from current and returns a new object
			-- Was declared in VALUE as synonym of minus.
		local
			res, empty: STRING_8
			r1, r2: VALUE
			r1i, r2i, d1, d2, dp, i, j: INTEGER_32
			ch: CHARACTER_8
		do
			r1 := Current.clone_me
			r2 := other.clone_me
			if r1.s_.item (1) = '-' and r2.s_.item (1) /= '-' then
				create Result
				r1.negate
				Result := (r1 + r2).clone_me
				Result.negate
			elseif r1.s_.item (1) /= '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 + r2).clone_me
			elseif r1.s_.item (1) = '-' and r2.s_.item (1) = '-' then
				create Result
				r2.negate
				Result := (r1 + r2).clone_me
			else
				if r1 < r2 then
					Result := (r2 - r1).clone_me
					Result.negate
				else
					r1.aligndecimal (r2)
					r1.alignwhole (r2)
					empty := ""
					res := empty.twin
					from
						r1i := r1.s_.count
						r2i := r2.s_.count
					until
						r1i < 1 or r2i < 1
					loop
						ch := '0'
						if r1.s_.item (r1i) /= '.' and r2.s_.item (r2i) /= '.' then
							d1 := todigit (r1.s_.item (r1i))
							d2 := todigit (r2.s_.item (r2i))
							if d1 < d2 then
								from
									i := r1i - 1
								until
									i < 1
								loop
									if r1.s_.item (i) /= '.' then
										dp := todigit (r1.s_.item (i))
										if dp > 0 then
											r1.s_.put (tochar (dp - 1), i)
											from
												j := i + 1
											until
												j > r1i - 1
											loop
												if r1.s_.item (j) /= '.' then
													r1.s_.put (tochar (todigit (r1.s_.item (j)) + 9), j)
												end
												j := j + 1
											end
											d1 := d1 + 10
											i := 0
										end
									end
									i := i - 1
								end
							end
							ch := tochar (d1 - d2)
						elseif r1.s_.item (r1i) = '.' and r2.s_.item (r2i) = '.' then
							ch := '.'
						end
						res.insert_character (ch, 1)
						r1i := r1i - 1
						r2i := r2i - 1
					end
					create Result.make_from_string (res)
				end
			end
		end

	zero: VALUE
			-- neutral element for "+" and "-"
		do
			create Result.make_from_string ("0")
		ensure -- from NUMERIC
			result_exists: Result /= Void
		end
	
feature -- printing

	out: STRING_8
			-- return a representation of the number rounded to two decimal places
		require -- from  DEBUG_OUTPUT
			True
		require -- from  ANY
			True
		local
			myclone: VALUE
			precision, missingzeros, idxdot, rounddigits: INTEGER_32
			pad: STRING_8
		do
			myclone := Current.clone_me
			rounddigits := 2
			myclone.round (rounddigits)
			idxdot := myclone.s_.index_of ('.', 1)
			if idxdot = 0 then
				myclone.s_.append_character ('.')
				create pad.make_filled ('0', rounddigits)
				myclone.s_.append_string (pad)
			else
				precision := myclone.s_.count - idxdot
				missingzeros := rounddigits - precision
				if missingzeros > 0 then
					create pad.make_filled ('0', missingzeros)
					myclone.s_.append_string (pad)
				end
			end
			Result := myclone.s_.twin
		ensure -- from DEBUG_OUTPUT
			result_not_void: Result /= Void
		ensure -- from ANY
			out_not_void: Result /= Void
		end

	precise_out: STRING_8
			-- what is the string representation of VALUE_IMP
		do
			Result := s_.twin
		end
	
feature {VALUE} -- private fields	

	clone_me: VALUE
		local
			l_s: STRING_8
		do
			create l_s.make_from_string (s_)
			create Result.make (l_s, divisiondecimalprecision_)
		end

	Default_precision: INTEGER_32 = 35

	divisiondecimalprecision_: INTEGER_32
			-- the minimum accuracy of division results; division results will be accurate to AT LEAST this many digits

	make (s: STRING_8; dv: INTEGER_32)
			-- create a MONEY_VALUE object from string s
		require
			non_void: s /= Void
			non_empty: not s.is_empty
			has_correct_format: ensurevalid (s)
		do
			divisiondecimalprecision_ := dv
			s_ := s
		end

	s_: STRING_8
	
feature {VALUE} -- private methods

	aligndecimal (other: VALUE)
			-- used to align the fractional parts of the given parameters
		local
			mydotpos, otherdotpos, myprec, otherprec, numtopad, i: INTEGER_32
			pad: detachable STRING_8
		do
			mydotpos := s_.index_of ('.', 1)
			otherdotpos := other.s_.index_of ('.', 1)
			if mydotpos /= 0 and otherdotpos /= 0 then
				myprec := s_.count - mydotpos
				otherprec := other.s_.count - otherdotpos
				if myprec /= otherprec then
					pad := Void
					if myprec < otherprec then
						pad := s_
					else
						pad := other.s_
					end
					numtopad := (myprec - otherprec).abs
					from
						i := 1
					until
						i > numtopad
					loop
						pad.append_character ('0')
						i := i + 1
					end
				end
			elseif mydotpos /= 0 or otherdotpos /= 0 then
				if mydotpos /= 0 then
					myprec := s_.count - mydotpos
				else
					myprec := 0
				end
				if otherdotpos /= 0 then
					otherprec := other.s_.count - otherdotpos
				else
					otherprec := 0
				end
				pad := Void
				if myprec < otherprec then
					pad := s_
				else
					pad := other.s_
				end
				numtopad := (myprec - otherprec).abs
				pad.append_character ('.')
				from
					i := 1
				until
					i > numtopad
				loop
					pad.append_character ('0')
					i := i + 1
				end
			end
		end

	alignwhole (other: VALUE)
			-- used to align the integer parts of the given parameters
		local
			mydotpos, otherdotpos, mywholelength, otherwholelength, menegoffset, othernegoffset, inspos, numtopad, i: INTEGER_32
			meneg, otherneg: BOOLEAN
			pad: detachable STRING_8
		do
			mydotpos := s_.index_of ('.', 1)
			otherdotpos := other.s_.index_of ('.', 1)
			meneg := s_.item (1) = '-'
			otherneg := other.s_.item (1) = '-'
			if mydotpos /= 0 then
				if meneg then
					menegoffset := 1
				else
					menegoffset := 0
				end
				mywholelength := mydotpos - menegoffset - 1
			else
				mywholelength := s_.count
			end
			if otherdotpos /= 0 then
				if otherneg then
					othernegoffset := 1
				else
					othernegoffset := 0
				end
				otherwholelength := otherdotpos - othernegoffset - 1
			else
				otherwholelength := other.s_.count
			end
			if mywholelength /= otherwholelength then
				pad := Void
				if mywholelength < otherwholelength then
					pad := s_
				else
					pad := other.s_
				end
				inspos := 1
				if pad.item (1) = '-' then
					inspos := inspos + 1
				end
				numtopad := (mywholelength - otherwholelength).abs
				from
					i := 1
				until
					i > numtopad
				loop
					pad.insert_character ('0', inspos)
					i := i + 1
				end
			end
		end

	ensurevalid (s: STRING_8): BOOLEAN
			-- check if the given string is of the correct format
		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

	normalize
			-- standardizes the format of the real number
		require
			non_empty: not s_.is_empty
		local
			i, inspos, dotpos, firstnonzeropos, lastnonzeropos: INTEGER_32
			seenminus, prependzero, hasdot: BOOLEAN
			whole, fraction, empty, tmp, zerostr: STRING_8
		do
			empty := ""
			zerostr := "0"
			seenminus := False
			prependzero := False
			from
				i := 1
			until
				i > s_.count
			loop
				if s_.item (i) = '-' then
					seenminus := True
				elseif s_.item (i) = '.' then
					if i = 1 or seenminus then
						prependzero := True
					end
				end
				i := i + 1
			end
			if prependzero then
				inspos := 1
				if seenminus then
					inspos := 2
				end
				s_.insert_character ('0', inspos)
			end
			if (seenminus) then
				negate
			end
			dotpos := s_.index_of ('.', 1)
			if dotpos = 0 then
				hasdot := False
				whole := s_.twin
				fraction := empty.twin
			else
				hasdot := True
				tmp := s_.substring (1, dotpos - 1)
				whole := tmp.twin
				tmp := s_.substring (dotpos + 1, s_.count)
				fraction := tmp.twin
			end
			if not whole.is_empty then
				firstnonzeropos := whole.count + 1
				from
					i := 1
				until
					i > whole.count
				loop
					if whole.item (i) /= '0' then
						firstnonzeropos := i
						i := whole.count + 1
					end
					i := i + 1
				end
				if firstnonzeropos = whole.count + 1 then
					whole := zerostr.twin
				else
					tmp := whole.substring (firstnonzeropos, whole.count)
					whole := tmp.twin
				end
			end
			if not fraction.is_empty then
				lastnonzeropos := -1
				from
					i := fraction.count
				until
					i < 1
				loop
					if fraction.item (i) /= '0' then
						lastnonzeropos := i
						i := 0
					end
					i := i - 1
				end
				if lastnonzeropos = -1 then
					fraction := empty.twin
				else
					tmp := fraction.substring (1, lastnonzeropos)
					fraction := tmp.twin
				end
			end
			s_ := whole.twin
			if hasdot and not fraction.is_empty then
				s_.append (".")
				s_.append (fraction)
			end
			if seenminus and not s_.is_equal ("0") then
				s_.insert_character ('-', 1)
			end
		end

	tochar (d: INTEGER_32): CHARACTER_8
			-- converts a digit to a character
		local
			chzero: CHARACTER_8
		do
			chzero := '0'
			Result := (chzero.code + d).to_character_8
		end

	todigit (ch: CHARACTER_8): INTEGER_32
			-- converts a character to a digit
		local
			chzero: CHARACTER_8
		do
			chzero := '0'
			Result := ch.code - chzero.code
		end
	
feature -- rounding

	absolute: VALUE
		do
			if Current >= Current.zero then
				Result := Current.clone_me
			else
				Result := opposite.clone_me
			end
		ensure
				Result >= Result.zero
		end

	Epsilon_singleton: VALUE_SINGLETON
		once
			create Result
		end

	is_imprecise_equal alias "|~" (other: VALUE): BOOLEAN
		do
			if Epsilon_singleton.epsilon = create {VALUE}.make_from_string ("0.0") then
				Result := Current = other
			else
				Result := (Current - other).absolute <= Epsilon_singleton.epsilon
			end
		end

	is_imprecise_equal_negation alias "|/~" (other: VALUE): BOOLEAN
		do
			if Epsilon_singleton.epsilon = create {VALUE}.make_from_string ("0.0") then
				Result := Current /= other
			else
				Result := not (Current |~ other)
			end
		end

	is_imprecise_greater alias "|>" (other: VALUE): BOOLEAN
		do
			if Epsilon_singleton.epsilon = create {VALUE}.make_from_string ("0.0") then
				Result := Current > other
			else
				Result := Current > (other + Epsilon_singleton.epsilon)
			end
		end

	is_imprecise_greater_equal alias "|>~" (other: VALUE): BOOLEAN
		do
			if Epsilon_singleton.epsilon = create {VALUE}.make_from_string ("0.0") then
				Result := Current >= other
			else
				Result := (Current |~ other) or (Current > (other + Epsilon_singleton.epsilon))
			end
		end

	is_imprecise_less alias "|<" (other: VALUE): BOOLEAN
		do
			if Epsilon_singleton.epsilon = create {VALUE}.make_from_string ("0.0") then
				Result := Current < other
			else
				Result := Current < (other - Epsilon_singleton.epsilon)
			end
		end

	is_imprecise_less_equal alias "|<~" (other: VALUE): BOOLEAN
		do
			if Epsilon_singleton.epsilon = create {VALUE}.make_from_string ("0.0") then
				Result := Current <= other
			else
				Result := (Current |~ other) or (Current < (other - Epsilon_singleton.epsilon))
			end
		end

	negate
			-- negates the number
		local
			tmp: STRING_8
		do
			if s_.item (1) = '-' then
				tmp := s_.substring (2, s_.count)
				s_ := tmp.twin
			else
				s_.insert_character ('-', 1)
			end
		end

	precise_out_to (digits: INTEGER_32): STRING_8
			-- returns the precise string representation to 'digits'
		require
				digits >= 0
		local
			dotpos: INTEGER_32
		do
			Result := precise_out
			dotpos := Result.index_of ('.', 1)
			if dotpos > 0 then
				Result := Result.substring (1, dotpos + digits)
			end
		end

	round (digits: INTEGER_32)
			-- rounds this instance to the specified number of digits
		require
				digits >= 0
		local
			dotpos: INTEGER_32
			neg: BOOLEAN
			s, tmp: STRING_8
			x, y: VALUE
		do
			dotpos := s_.index_of ('.', 1)
			if dotpos > 0 then
				neg := False
				if s_.item (1) = '-' then
					negate
					neg := True
				end
				create s.make_filled ('0', digits)
				s.append ("5")
				s.insert_string ("0.", 1)
				create x.make_from_string (s)
				y := Current + x
				dotpos := y.s_.index_of ('.', 1)
				if dotpos /= 0 then
					tmp := y.s_.substring (1, dotpos + digits)
				else
					tmp := y.precise_out
				end
				s_ := tmp.twin
				if neg then
					negate
				end
			end
			normalize
		end

	round_to (digits: INTEGER_32): VALUE
			-- rounds the current VALUE_IMP to 'digits'
			-- symmetric rounding as in Excel http://support.microsoft.com/kb/196652
			-- -2.6 is rounded to -3
		require
				digits >= 0
		do
			Result := Current.clone_me
			Result.round (digits)
		end

	set_epsilon (v: STRING_8)
		do
			Epsilon_singleton.set_epsilon (v)
		end
	
invariant
		divisiondecimalprecision_ > 0

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

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

end -- class VALUE

Generated by ISE EiffelStudio