note
	description: "Summary description for {INTEGER_X_DIVISION}."
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "Collecting more taxes than is absolutely necessary is legalized robbery. -  President Calvin Coolidge"

deferred class
	INTEGER_X_DIVISION

inherit
	INTEGER_X_FACILITIES
	SPECIAL_UTILITY
		export
			{NONE}
				all
		end
	SPECIAL_DIVISION
		rename
			add as add_special,
			sub as sub_special,
			mul as mul_special,
			tdiv_qr as tdiv_qr_special
		export
			{NONE}
				all
		end
	INTEGER_X_ARITHMETIC
	INTEGER_X_ASSIGNMENT
		rename
			add as add_special,
			sub as sub_special,
			mul as mul_special
		export
			{NONE}
				all
		end

feature

	fdiv_r_2exp (target: READABLE_INTEGER_X; u: READABLE_INTEGER_X; count: INTEGER)
		do
			cfdiv_r_2exp (target, u, count, -1)
		end

	cdiv_r_2exp (target: READABLE_INTEGER_X; u: READABLE_INTEGER_X; count: INTEGER)
		do
			cfdiv_r_2exp (target, u, count, 1)
		end

	cfdiv_r_2exp (target: READABLE_INTEGER_X; u: READABLE_INTEGER_X; count_a: INTEGER; direction: INTEGER)
		local
			usize: INTEGER
			abs_usize: INTEGER
			limb_count: INTEGER
			i: INTEGER
			up: SPECIAL [NATURAL_32]
			up_offset: INTEGER
			wp: SPECIAL [NATURAL_32]
			wp_offset: INTEGER
			high: NATURAL_32
			count: INTEGER
			returned: BOOLEAN
			negate: BOOLEAN
		do
			create wp.make_empty (0)
			count := count_a
			usize := u.count
			if usize = 0 then
				target.count := 0
			else
				limb_count := count // 32
				count := count \\ 32
				abs_usize := usize.abs
				up := u.item
				if usize.bit_xor (direction) < 0 and Current = u and abs_usize <= limb_count then
					returned := True
				else
					if usize.bit_xor (direction) < 0 then
						if Current = u then
							wp := target.item
						else
							i := abs_usize.min (limb_count + 1)
							target.resize (i)
							wp := target.item
							wp.copy_data (up, up_offset, wp_offset, i)
							if abs_usize <= limb_count then
								target.count := usize
								returned := True
							end
						end
					else
						if abs_usize <= limb_count then
							negate := True
						else
							from
								i := 0
							until
								i < limb_count or negate
							loop
								negate := up [up_offset + i] /= 0
								i := i + 1
							end
							if not negate then
								if up [up_offset + limb_count].bit_and (((1).to_natural_32 |<< count) - 1) /= 0 then
									negate := True
								else
									target.count := 0
									returned := True
								end
							end
						end
						if not returned and negate then
							target.resize (limb_count + 1)
							up := u.item
							up_offset := 0
							wp := target.item
							wp_offset := 0
							i := abs_usize.min (limb_count + 1)
							com_n (wp, wp_offset, up, up_offset, i)
							from
							until
								i > limb_count
							loop
								wp [wp_offset + i] := high.max_value
								i := i + 1
							end
							incr_u (wp, wp_offset, 1)
							usize := -usize
						end
					end
				end
				if not returned then
					high := wp [wp_offset + limb_count]
					high := high.bit_and (((1).to_natural_32 |<< count) - 1)
					wp [wp_offset + limb_count] := high
					from
						limb_count := limb_count - 1
					until
						high /= 0 or limb_count < 0
					loop
						high := wp [wp_offset + limb_count]
					end
					if limb_count < 0 then
						target.count := 0
					else
						limb_count := limb_count + 1
						if usize >= 0 then
							target.count := limb_count
						else
							target.count := -limb_count
						end
					end
				end
			end
		end

	mod (target: READABLE_INTEGER_X; dividend: READABLE_INTEGER_X; divisor_a: READABLE_INTEGER_X)
		local
			divisor_size: INTEGER
			temp_divisor: INTEGER_X
			divisor: READABLE_INTEGER_X
		do
			divisor := divisor_a
			divisor_size := divisor.count
			if target = divisor then
				create temp_divisor.make_limbs (divisor_size.abs)
				temp_divisor.set_from_other (divisor)
				divisor := temp_divisor
			end
			tdiv_r (target, dividend, divisor)
			if target.count /= 0 then
				if dividend.count < 0 then
					if divisor.count < 0 then
						sub (target, target, divisor)
					else
						add (target, target, divisor)
					end
				end
			end
		end

	tdiv_q (target: READABLE_INTEGER_X; numerator: READABLE_INTEGER_X; denominator: READABLE_INTEGER_X)
		local
			ql: INTEGER
			ns: INTEGER
			ds: INTEGER
			nl: INTEGER
			dl: INTEGER
			np: SPECIAL [NATURAL_32]
			np_offset: INTEGER
			dp: SPECIAL [NATURAL_32]
			dp_offset: INTEGER
			qp: SPECIAL [NATURAL_32]
			qp_offset: INTEGER
			rp: SPECIAL [NATURAL_32]
			rp_offset: INTEGER
			tp: SPECIAL [NATURAL_32]
			tp_offset: INTEGER
		do
			ns := numerator.count
			ds := denominator.count
			nl := ns.abs
			dl := ds.abs
			ql := nl - dl + 1

			if dl = 0 then
				(create {DIVIDE_BY_ZERO}).raise
			end
			if ql <= 0 then
				target.count := 0
			else
				target.resize (ql)
				qp := target.item
				create rp.make_filled (0, dl)
				np := numerator.item
				dp := denominator.item
				if dp = qp then
					create tp.make_filled (0, dl)
					tp.copy_data (dp, dp_offset, tp_offset, dl)
					dp := tp
				end
				if np = qp then
					create tp.make_filled (0, nl)
					tp.copy_data (np, np_offset, tp_offset, nl)
					np := tp
				end
				tdiv_qr_special (qp, qp_offset, rp, rp_offset, np, np_offset, nl, dp, dp_offset, dl)
				ql := ql - (qp [qp_offset + ql - 1] = 0).to_integer
				if ns.bit_xor (ds) >= 0 then
					target.count := ql
				else
					target.count := -ql
				end
			end
		end

	tdiv_q_2exp (target: READABLE_INTEGER_X; op: READABLE_INTEGER_X; count_a: INTEGER_32)
		local
			usize: INTEGER
			wsize: INTEGER
			limb_count: INTEGER
			wp: SPECIAL [NATURAL_32]
			wp_offset: INTEGER
			up: SPECIAL [NATURAL_32]
			up_offset: INTEGER
			junk: NATURAL_32
			count: INTEGER_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			count := count_a
			usize := op.count
			limb_count := count // 32
			wsize := usize.abs - limb_count
			if wsize <= 0 then
				target.count := 0
			else
				target.resize (wsize)
				wp := target.item
				up := op.item
				count := count \\ 32
				if count /= 0 then
					rshift (wp, wp_offset, up, up_offset + limb_count, wsize, count, carry)
					junk := carry.item
					wsize := wsize - (wp [wp_offset + wsize - 1] = 0).to_integer
				else
					wp.copy_data (up, up_offset + limb_count, wp_offset, wsize)
				end
				if usize >= 0 then
					target.count := wsize
				else
					target.count := -wsize
				end
			end
		end

	tdiv_qr (target: READABLE_INTEGER_X; remainder: READABLE_INTEGER_X; numerator: READABLE_INTEGER_X; denominator: READABLE_INTEGER_X)
		local
			ql: INTEGER_32
			ns: INTEGER_32
			ds: INTEGER_32
			nl: INTEGER_32
			dl: INTEGER_32
			temp_dp: SPECIAL [NATURAL_32]
			temp_np: SPECIAL [NATURAL_32]
		do
			ns := numerator.count
			ds := denominator.count
			nl := ns.abs
			dl := ds.abs
			ql := nl - dl + 1
			if dl = 0 then
				(create {DIVIDE_BY_ZERO}).raise
			end
			remainder.resize (dl)
			if ql <= 0 then
				if numerator /= remainder then
					remainder.item.copy_data (numerator.item, 0, 0, nl)
					remainder.count := numerator.count
				end
				target.count := 0
			else
				target.resize (ql)
				if denominator = remainder or denominator = Current then
					create temp_dp.make_empty (dl)
					temp_dp.copy_data (denominator.item, 0, 0, dl)
				else
					temp_dp := denominator.item
				end
				if numerator = remainder or numerator = Current then
					create temp_np.make_empty (nl)
					temp_np.copy_data (numerator.item, 0, 0, nl)
				else
					temp_np := numerator.item
				end
				tdiv_qr_special (target.item, 0, remainder.item, 0, temp_np, 0, nl, temp_dp, 0, dl)
				if target.item [ql - 1] = 0 then
					ql := ql - 1
				end
				remainder.count :=  normalize (remainder.item, 0, remainder.count)
				dl := remainder.count
				if ns.bit_xor (ds) >= 0 then
					target.count := ql
				else
					target.count := -ql
				end
				if ns >= 0 then
					remainder.count := dl
				else
					remainder.count := -dl
				end
			end
		end

	tdiv_r (remainder: READABLE_INTEGER_X; numerator: READABLE_INTEGER_X; denominator: READABLE_INTEGER_X)
		local
			ql: INTEGER
			ns: INTEGER
			ds: INTEGER
			nl: INTEGER
			dl: INTEGER
			np: SPECIAL [NATURAL_32]
			np_offset: INTEGER
			dp: SPECIAL [NATURAL_32]
			dp_offset: INTEGER
			qp: SPECIAL [NATURAL_32]
			qp_offset: INTEGER
			rp: SPECIAL [NATURAL_32]
			rp_offset: INTEGER
			tp: SPECIAL [NATURAL_32]
			tp_offset: INTEGER
		do
			ns := numerator.count
			ds := denominator.count
			nl := ns.abs
			dl := ds.abs
			ql := nl - dl + 1
			if dl = 0 then
				(create {DIVIDE_BY_ZERO}).raise
			end
			remainder.resize (dl)
			if ql <= 0 then
				if numerator /= remainder then
					np := numerator.item
					rp := remainder.item
					rp.copy_data (np, 0, 0, nl)
					remainder.count := numerator.count
				end
			else
				create qp.make_filled (0, ql)
				rp := remainder.item
				np := numerator.item
				dp := denominator.item
				if dp = rp then
					create tp.make_filled (0, nl)
					tp.copy_data (np, np_offset, tp_offset, nl)
					np := tp
					np_offset := tp_offset
				end
				tdiv_qr_special (qp, qp_offset, rp, rp_offset, np, np_offset, nl, dp, dp_offset, dl)
				dl := normalize (rp, rp_offset, dl)
				if ns >= 0 then
					remainder.count := dl
				else
					remainder.count := -dl
				end
			end
		end

	tdiv_r_2exp (target: READABLE_INTEGER_X; op: READABLE_INTEGER_X; count: INTEGER)
		local
			in_size: INTEGER
			res_size: INTEGER
			limb_count: INTEGER
			in_ptr: SPECIAL [NATURAL_32]
			in_ptr_offset: INTEGER
			x: NATURAL_32
		do
			in_size := op.count.abs
			limb_count := count // 32
			in_ptr := op.item
			if in_size > limb_count then
				x := in_ptr [in_ptr_offset + limb_count].bit_and (((1).to_natural_32 |<< (count \\ 32)- 1))
				if x /= 0 then
					res_size := limb_count + 1
					target.resize (res_size)
					target.item [limb_count] := x
				else
					res_size := limb_count
					res_size := normalize (in_ptr, in_ptr_offset, res_size)
					target.resize (res_size)
					limb_count := res_size
				end
			else
				res_size := in_size
				target.resize (res_size)
				limb_count := res_size
			end
			if target /= op then
				target.item.copy_data (op.item, 0, 0, limb_count)
			end
			if op.count >= 0 then
				target.count := res_size
			else
				target.count := -res_size
			end
		end
end
