note
	description: "[
				An arbitrary precision library for decimal numbers. 
				Following the 'General Decimal Arithmetic Specification' of gobo MA_DECIMAL.
				
				Creation
					make_from_string
					make_from_decimal
					make_from_int
					make_from_big_int
					make_from_rational
		
				Queries
					as_big_int: BIG_INTEGER
					as_rational: RATIONAL
					as_real32: REAL_32
					as_real64: REAL_64
					exp alias "^" (power: DECIMAL): DECIMAL
					identity alias "+": DECIMAL
					is_equal (other: DECIMAL): BOOLEAN
					is_greater alias ">" (other: DECIMAL): BOOLEAN
					is_greater_equal alias ">=" (other: DECIMAL): BOOLEAN
					is_integer: BOOLEAN
					is_less alias "<" (other: DECIMAL): BOOLEAN
					is_less_equal alias "<=" (other: DECIMAL): BOOLEAN
					is_natural: BOOLEAN
					is_natural1: BOOLEAN
					is_negative: BOOLEAN
					is_real32: BOOLEAN
					is_real64: BOOLEAN
					max (other: DECIMAL): DECIMAL
					min (other: DECIMAL): DECIMAL
					minus alias "-" (other: DECIMAL): DECIMAL
					one: DECIMAL
					opposite alias "-": DECIMAL
					out: STRING
					plus alias "+" (other: DECIMAL): DECIMAL
					precise_out: STRING
					precise_out_to (digits: INTEGER): STRING
					product alias "*" (other: DECIMAL): DECIMAL
					quotient alias "/" (other: DECIMAL): DECIMAL
					sqrt: DECIMAL
					round_to (digits: INTEGER): DECIMAL
					zero: DECIMAL
		
				Commands
					round (digits: INTEGER)
					set_precision (precision: INTEGER)
	]"
	author: "JSO, DC, and CD"
	date: "$Date$"
	revision: "$Revision$"

class interface
	DECIMAL

create 
	make_from_string,
	make_from_decimal,
	make_from_int,
	default_create,
	make_from_string_ctx,
	make_with_precision,
	make_from_big_int,
	make_from_rational

convert
	make_from_string ({STRING_8}),
	make_from_big_int ({BIG_INTEGER}),
	make_from_rational ({RATIONAL}),
	as_real64: {REAL_64},
	as_big_int: {BIG_INTEGER},
	as_rational: {RATIONAL},
	out: {STRING_8}

feature -- comparison

	is_equal (other: DECIMAL): BOOLEAN
			-- check whether other is equal to current or not

	is_less alias "<" (other: DECIMAL): BOOLEAN
			-- whether current is less than other
	
feature -- operations

	plus alias "+" (other: DECIMAL): DECIMAL
			-- adds current to other and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of add.

	add (other: DECIMAL): DECIMAL
			-- adds current to other and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of plus.

	minus alias "-" (other: DECIMAL): DECIMAL
			-- subtracts other from current and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of subtract.

	subtract (other: DECIMAL): DECIMAL
			-- subtracts other from current and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of minus.

	product alias "*" (other: DECIMAL): DECIMAL
			-- multiplies current by other and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of multiply.

	multiply (other: DECIMAL): DECIMAL
			-- multiplies current by other and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of product.

	quotient alias "/" (other: DECIMAL): DECIMAL
			-- divides current by other and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of divide.
		require
			other_non_zero: other /~ zero

	divide (other: DECIMAL): DECIMAL
			-- divides current by other and returns a new object
			-- The new DECIMAL will have a precision based on the criteria in calculate_new_precision
			-- Was declared in DECIMAL as synonym of quotient.
		require
			other_non_zero: other /~ zero

	sqrt: DECIMAL
			-- calculates square root for this instance
		require
			non_negative: not is_negative

	exp alias "^" (p: DECIMAL): DECIMAL
			-- calculates the value of current instance raised to 'power' (capped to 500 digits of precision)
			-- Was declared in DECIMAL as synonym of exponent and power.
		require
			is_exponentiable: exponentiable (p)

	exponent (p: DECIMAL): DECIMAL
			-- calculates the value of current instance raised to 'power' (capped to 500 digits of precision)
			-- Was declared in DECIMAL as synonym of exp and power.
		require
			is_exponentiable: exponentiable (p)

	power (p: DECIMAL): DECIMAL
			-- calculates the value of current instance raised to 'power' (capped to 500 digits of precision)
			-- Was declared in DECIMAL as synonym of exp and exponent.
		require
			is_exponentiable: exponentiable (p)

	negate
			-- negates Current

	absolute: DECIMAL
			-- returns the absoulte value of Current

	floor: DECIMAL
			-- Returns the greatest integer less than or equal to Current

	ceiling: DECIMAL
			-- Returns the smallest integer greater than or equal to Current
	
feature -- conversion

	as_real32: REAL_32
			-- represent as a REAL_32
		require
			valid_real32: is_real32

	as_real64: REAL_64
			-- represent as a REAL_64
		require
			valid_real64: is_real64

	as_big_int: BIG_INTEGER
			-- Represent as BIG_INTEGER
		require
			is_integer: is_integer

	as_rational: RATIONAL
			-- Represent as RATIONAL
	
feature -- queries

	opposite alias "-": DECIMAL
			-- unary minus

	identity alias "+": DECIMAL
			-- unary plus

	is_natural: BOOLEAN
			-- Is Current an Natural number?

	is_natural1: BOOLEAN
			-- Is Current an Natural1 number?

	is_integer: BOOLEAN
			-- Is Current an integer number?

	is_real32: BOOLEAN

	is_real64: BOOLEAN
			-- Is Current a double?

	is_negative: BOOLEAN
			-- Is Current less than or equal to zero?

	debug_output: STRING_8
			-- String that should be displayed in debugger to represent Current.

	out: STRING_8
			-- return a representation of the number rounded to two decimal places

	precise_out: STRING_8
			-- return precise representation of the number

	zero: DECIMAL
			-- neutral element for "+" and "-"

	one: DECIMAL
			-- neutral element for "*" and "/"

	divisible (other: DECIMAL): BOOLEAN
			-- may current object be divided by other?

	exponentiable (other: DECIMAL): BOOLEAN
			-- may current object be elevated to the power other?
	
feature -- rounding

	round_to (digits: INTEGER_32): DECIMAL
			-- Returns a decimal that is the current value rounded to the specified 'digits' number of decimal places
			-- Uses default strategy as set in ma_decimal_ctx (half up)
		require
			positive_digits: digits >= 0

	round (digits: INTEGER_32)
			-- rounds this instance to the specified digits number of decimal places
		require
			positive_digits: digits >= 0

	precise_out_to (digits: INTEGER_32): STRING_8
			-- returns the precise string representation to rounded to the specified 'digits' number of decimal places
		require
			positive_digits: digits >= 0

	set_precision (precision: INTEGER_32)
			-- sets the precision of Current for future operations
		require
			precision_positive: precision > 0

	reset_precision
			-- resets the precision of Current for future operations to Default_precision

	get_precision: INTEGER_32
			-- returns the current number of digits being kept by the number
	
invariant
	consistent_rounding: Default_rounding = {MA_DECIMAL_CONTEXT}.round_half_up

note
	info: "[
		 For an oracle see http://delaneyrm.com/MPCalcRB.html.
		 
		 test: BOOLEAN
			local
				d1, d2, d3, d4, d5, d6: DECIMAL
				r64: REAL_64
				i: INTEGER
				r: RATIONAL
			do
				comment ("test: Mortgage Calculation in REAL_64 vs DECIMAL")
				-- floating point arithmetic cannot distinguish
				-- between 0.4 and 0.40000000000000002
				r64 := 0.1 + 0.3
				Result := r64 = 0.4 and r64 = 0.40000000000000002
				check Result end
				-- decimal arithmetic can
				d1 := "0.1" ; d2 := "0.3"
				d3 := d1 + d2
				Result := d3 ~ "0.4"and d3 /~ "0.40000000000000002"
				check Result end
				assert_equal ("precise_out test", "0.4", d3.precise_out)
				assert_equal ("out test1", "0.40", d3.out)
				r64 := 100000*(1+0.05/12)^360
				Result := r64 = 446774.43140061089
				check Result end
				d1 := "100000" d2 := "0.05"; d3 := "12"; d4 := "360"
				d2.set_precision(120)
				d5 := d1 * (d1.one + d2/d3)^d4
				Result := d5.precise_out.starts_with ("446774.431400613221242807011041301589597772674487270698002439224547330881614835011308578390042190134313238565062087470576")
				check Result end
				assert_equal ("out test2", "446774.43", d5.out)
				d6 := d5 - "446774.43140061089"
				Result := d6.precise_out.starts_with ("0.000000002331242807011041301589597772674487270698002439224547330881614835011308578390042190134313238565062087470576")
				check
					 Result
				end
			end
	]"

end -- class DECIMAL

Generated by ISE EiffelStudio