note
	description: "Summary description for {NUMBER_DIVISION}."
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "Freedom is the emancipation from the arbitrary rule of other men. -  Mortimer Adler (1902-2001)"

deferred class
	SPECIAL_DIVISION

inherit
	SPECIAL_ARITHMETIC
	SPECIAL_COMPARISON
	LIMB_MANIPULATION
	SPECIAL_LOGIC

feature

	bdivmod (qp: SPECIAL [NATURAL_32]; qp_offset_a: INTEGER; up: SPECIAL [NATURAL_32]; up_offset_a: INTEGER; usize_a: INTEGER; vp: SPECIAL [NATURAL_32]; vp_offset: INTEGER; vsize: INTEGER; d_a: INTEGER): NATURAL_32
			-- Computes (`up' / `vp') mod (2 ^ `d')
		require
			usize_a >= 1
			vsize >= 1
			usize_a * limb_bits >= d_a
			vp.valid_index (vp_offset)
			vp.valid_index (vp_offset + vsize - 1)
			up.valid_index (up_offset_a)
			up.valid_index (up_offset_a + usize_a - 1)
			vp [vp_offset].bit_test (0)
		local
			v_inv: NATURAL_32
			hi: CELL [NATURAL_32]
			lo: CELL [NATURAL_32]
			q: NATURAL_32
			b: NATURAL_32
			junk: NATURAL_32
			d: INTEGER
			up_offset: INTEGER
			usize: INTEGER
			qp_offset: INTEGER
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			qp_offset := qp_offset_a
			up_offset := up_offset_a
			usize := usize_a
			d := d_a
			create hi.put (0)
			create lo.put (0)
			v_inv := modlimb_invert (vp [vp_offset])
			if usize = 2 and vsize = 2 and (d = limb_bits or d = 2 * limb_bits) then
				q := up [up_offset] * v_inv
				umul_ppmm (hi, lo, q, vp [vp_offset])
				up [up_offset] := 0
				up [up_offset + 1] := up [up_offset + 1] - hi.item + q * vp [vp_offset + 1]
				qp [qp_offset] := q
				if d = 2 * limb_bits then
					q := up [up_offset + 1] * v_inv
					up [up_offset + 1] := 0
					qp [qp_offset + 1] := q
				end
				Result := 0
			else
				from
				until
					d < limb_bits
				loop
					q := up [up_offset] * v_inv
					submul_1 (up, up_offset, vp, vp_offset, usize.min (vsize), q, carry)
					b := carry.item
					if usize > vsize then
						sub_1 (up, up_offset + vsize, up, up_offset + vsize, usize - vsize, b, carry)
						junk := carry.item
					end
					d := d - limb_bits
					up_offset := up_offset + 1
					usize := usize - 1
					qp [qp_offset] := q
					qp_offset := qp_offset + 1
				end
				if d /= 0 then
					q := (up [up_offset] * v_inv).bit_and (((1).to_natural_32 |<< d) - 1)
					if q <= 1 then
						if q = 0 then
							Result := 0
						else
							sub_n (up, up_offset, up, up_offset, vp, vp_offset, usize.min (vsize), carry)
							b := carry.item
							if usize > vsize then
								sub_1 (up, up_offset + vsize, up, up_offset + vsize, usize - vsize, b, carry)
								junk := carry.item
							end
							Result := q
						end
					else
						submul_1 (up, up_offset, vp, vp_offset, usize.min (vsize), q, carry)
						b := carry.item
						if usize > vsize then
							sub_1 (up, up_offset + vsize, up, up_offset + vsize, usize - vsize, b, carry)
							junk := carry.item
							Result := q
						end
					end
				else
					Result := 0
				end
			end
		end

	dc_divrem_n (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; op2: SPECIAL [NATURAL_32]; op2_offset: INTEGER_32; n: INTEGER_32): NATURAL_32
		local
			scratch: SPECIAL [NATURAL_32]
		do
			create scratch.make_filled (0, n)
			Result := dc_div_2_by_1 (target, target_offset, op1, op1_offset, op2, op2_offset, n, scratch, 0)
		end

	dc_div_2_by_1 (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; op2: SPECIAL [NATURAL_32]; op2_offset: INTEGER_32; n: INTEGER_32; scratch: SPECIAL [NATURAL_32]; scratch_offset: INTEGER_32): NATURAL_32
		local
			qhl: NATURAL_32
			cc: NATURAL_32
			n2: INTEGER_32
			target_cursor: INTEGER_32
			div_result: NATURAL_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			n2 := n // 2
			if n \\ 2 /= 0 then
				target_cursor := target_offset + 1
				qhl := dc_div_3_by_2 (target, target_cursor + n2, op1, op1_offset + 2 + n2, op2, op2_offset + 1, n2, scratch, scratch_offset)
				div_result := dc_div_3_by_2 (target, target_cursor, op1, op1_offset + 2, op2, op2_offset + 1, n2, scratch, scratch_offset)
				add_1 (target, target_cursor + n2, target, target_cursor + n2, n2, div_result, carry)
				qhl := qhl + carry.item
				submul_1 (op1, op1_offset + 1, target, target_cursor, n - 1, op2 [op2_offset], carry)
				cc := carry.item
				sub_1 (op1, op1_offset + n, op1, op1_offset + n, 1, cc, carry)
				cc := carry.item
				if qhl /= 0 then
					sub_1 (op1, op1_offset + n, op1, op1_offset + n, 1, op2 [op2_offset], carry)
					cc := cc + carry.item
				end
				from
				until
					cc = 0
				loop
					sub_1 (target, target_cursor, target, target_cursor, n - 1, 1, carry)
					qhl := qhl - carry.item
					add_n (op1, op1_offset + 1, op1, op1_offset + 1, op2, op2_offset, n, carry)
					cc := cc - carry.item
				end
				div_result := sb_divrem_mn (target, target_offset, op1, op1_offset, n + 1, op2, op2_offset, n)
				add_1 (target, target_cursor, target, target_cursor, n - 1, div_result, carry)
				qhl := qhl + carry.item
			else
				qhl := dc_div_3_by_2 (target, target_offset + n2, op1, op1_offset + n2, op2, op2_offset, n2, scratch, scratch_offset)
				div_result := dc_div_3_by_2 (target, target_offset, op1, op1_offset, op2, op2_offset, n2, scratch, scratch_offset)
				add_1 (target, target_offset + n2, target, target_offset + n2, n2, div_result, carry)
				qhl := qhl + carry.item
			end
			Result := qhl
		end

	dc_div_3_by_2 (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; op2: SPECIAL [NATURAL_32]; op2_offset: INTEGER_32; n: INTEGER_32; scratch: SPECIAL [NATURAL_32]; scratch_offset: INTEGER_32): NATURAL_32
		local
			twon: INTEGER_32
			qhl: NATURAL_32
			cc: NATURAL_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			twon := n + n
			if n < 3 * 32 then
				qhl := sb_divrem_mn (target, target_offset, op1, op1_offset + n, twon, op2, op2_offset + n, n)
			else
				qhl := dc_div_2_by_1 (target, target_offset, op1, op1_offset + n, op2, op2_offset + n, n, scratch, scratch_offset)
			end
			mul_n (scratch, scratch_offset, target, target_offset, op2, op2_offset, n)
			sub_n (op1, op1_offset, op1, op1_offset, scratch, scratch_offset, twon, carry)
			cc := carry.item
			if qhl /= 0 then
				sub_n (op1, op1_offset + n, op1, op1_offset + n, op2, op2_offset, n, carry)
				cc := cc + carry.item
			end
			from
			until
				cc = 0
			loop
				sub_1 (target, target_offset, target, target_offset, n, 1, carry)
				qhl := qhl - carry.item
				add_n (op1, op1_offset, op1, op1_offset, op2, op2_offset, twon, carry)
				cc := cc - carry.item
			end
			Result := qhl
		end

	divexact_1 (target: SPECIAL [NATURAL_32]; target_offset: INTEGER; src: SPECIAL [NATURAL_32]; src_offset: INTEGER; size_a: INTEGER; divisor_a: NATURAL_32)
		local
			i: INTEGER
			c: NATURAL_32
			h: CELL [NATURAL_32]
			l: NATURAL_32
			ls: NATURAL_32
			s: NATURAL_32
			s_next: NATURAL_32
			inverse: NATURAL_32
			dummy: CELL [NATURAL_32]
			shift: INTEGER
			divisor: NATURAL_32
			size: INTEGER
		do
			size := size_a
			divisor := divisor_a
			create h.put (0)
			create dummy.put (0)
			s := src [src_offset]
			if size = 1 then
				target [target_offset] := s // divisor
			elseif not divisor.bit_test (0) then
				shift := trailing_zeros (divisor)
				divisor := divisor |>> shift
			else
				shift := 0
			end
			inverse := limb_inverse (divisor)
			if shift /= 0 then
				c := 0
				i := 0
				size := size - 1
				from
				until
					i >= size
				loop
					s_next := src [src_offset + i + 1]
					ls := (s |>> shift).bit_or (s_next |<< (limb_bits - shift))
					s := s_next
					l := ls - c
					c := (l > ls).to_integer.to_natural_32
					l := l * inverse
					target [target_offset + i] := l
					umul_ppmm (h, dummy, l, divisor)
					c := c + h.item
					i := i + 1
				end
				ls := s |>> shift
				l := ls - c
				l := (l * inverse)
				target [target_offset + i] := l
			else
				l := s * inverse
				target [target_offset] := l
				i := 1
				c := 0
				from
				until
					i >= size
				loop
					umul_ppmm (h, dummy, l, divisor)
					c := c + h.item
					s := src [src_offset + i]
					l := s - c
					c := (l > s).to_integer.to_natural_32
					l := l * inverse
					target [target_offset + i] := l
					i := i + 1
				end
			end
		end

	divrem_2 (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; op1_count: INTEGER_32; op2: SPECIAL [NATURAL_32]; op2_offset: INTEGER_32): NATURAL_32
		require
			op2.valid_index (op2_offset)
			op2.valid_index (op2_offset + 1)
			op1_count >= 2
			op2 [op2_offset + 1].bit_and (0x80000000) /= 0
		local
			most_significant_q_limb: NATURAL_32
			i: INTEGER_32
			n1: CELL [NATURAL_32]
			n0: CELL [NATURAL_32]
			n2: NATURAL_32
			d1: NATURAL_32
			d0: NATURAL_32
			d1inv: NATURAL_32
			op1_cursor: INTEGER_32
			q: CELL [NATURAL_32]
			r: CELL [NATURAL_32]
			continue: BOOLEAN
		do
			create n1.put (0)
			create n0.put (0)
			create q.put (0)
			create r.put (0)
			op1_cursor := op1_offset + op1_count - 2
			d1 := op2 [op2_offset + 1]
			d0 := op2 [op2_offset]
			n1.put (op1 [op1_cursor + 1])
			n0.put (op1 [op1_cursor])
			if n1.item >= d1 and (n1.item > d1 or n0.item >= d0) then
				sub_ddmmss (n1, n0, n1.item, n0.item, d1, d0)
				most_significant_q_limb := 1
			end
			d1inv := limb_inverse (d1)
			from
				i := op1_count - 2 - 1
			until
				i < 0
			loop
				continue := False
				op1_cursor := op1_cursor - 1
				if n1.item = d1 then
					q.put (0xffffffff)
					r.put (n0.item + d1)
					if r.item < d1 then
						add_ssaaaa (n1, n0, r.item - d0, op1 [op1_cursor], 0, d0)
						target [target_offset + i] := q.item
						continue := True
					else
						n1.put (d0 - (d0 /= 0).to_integer.to_natural_32)
						n0.put (0 - d0)
					end
				else
					udiv_qrnnd_preinv (q, r, n1.item, n0.item, d1, d1inv)
					umul_ppmm (n1, n0, d0, q.item)
				end
				if not continue then
					n2 := op1 [op1_cursor]
					from
						continue := True
					until
						not continue
					loop
						if n1.item > r.item or (n1.item = r.item and n0.item > n2) then
							q.put (q.item - 1)
							sub_ddmmss (n1, n0, n1.item, n0.item, 0, d0)
							r.put (r.item + d1)
							if r.item >= d1 then
							else
								continue := False
							end
						else
							continue := False
						end
					end
					target [target_offset + i] := q.item
					sub_ddmmss (n1, n0, r.item, n2, n1.item, n0.item)
				end
				i := i - 1
			end
			op1 [op1_cursor + 1] := n1.item
			op1 [op1_cursor] := n0.item
			Result := most_significant_q_limb
		end

	sub_ddmmss (sh: CELL [NATURAL_32]; sl: CELL [NATURAL_32]; ah: NATURAL_32; al: NATURAL_32; bh: NATURAL_32; bl: NATURAL_32)
		local
			x: NATURAL_32
		do
			x := al - bl
			sh.put (ah - bh - (al < bl).to_integer.to_natural_32)
			sl.put (x)
		end

	divrem_1 (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; op1_count: INTEGER_32; d: NATURAL_32): NATURAL_32
		require
			d /= 0
			op1_count >= 0
		local
			n: INTEGER_32
			i: INTEGER_32
			n1: NATURAL_32
			n0: NATURAL_32
			r: NATURAL_32
			target_cursor: INTEGER_32
			q: NATURAL_32
			norm: INTEGER_32
			un: INTEGER_32
			dinv: NATURAL_32
			d_cursor: NATURAL_32
			q_res: CELL [NATURAL_32]
			r_res: CELL [NATURAL_32]
		do
			create q_res.put (0)
			create r_res.put (0)
			un := op1_count
			n := op1_count
			if n = 0 then
				Result := 0
			else
				target_cursor := target_offset + n - 1
				if d.bit_test (limb_high_bit) then
					r := op1 [op1_count - 1]
					q := (r >= d).to_integer.to_natural_32
					target [target_cursor] := q
					target_cursor := target_cursor - 1
					r := r - d.bit_and (0 - q)
					n := n - 1
					un := un - 1
					dinv := limb_inverse (d)
					from
						i := un - 1
					until
						i < 0
					loop
						n0 := op1 [i]
						udiv_qrnnd_preinv (q_res, r_res, r, n0, d, dinv)
						target [target_cursor] := q_res.item
						r := r_res.item
						target_cursor := target_cursor - 1
						i := i - 1
					end
					Result := r
				else
					n1 := op1 [op1_count - 1]
					Result := r - 1
					if n1 < d then
						r := n1
						target [target_cursor] := 0
						target_cursor := target_cursor - 1
						n := n - 1
						if n = 0 then
							Result := r
						else
							un := un - 1
						end
					end
					if Result /= r then
						norm := leading_zeros (d)
						d_cursor := d |<< norm
						r := r |<< norm
						dinv := limb_inverse (d_cursor)
						if un /= 0 then
							n1 := op1 [un - 1]
							r := r.bit_or (n1.bit_shift_right (-norm))
							from
								i := un - 2
							until
								i < 0
							loop
								n0 := op1 [i]
								udiv_qrnnd_preinv (q_res, r_res, r, n1.bit_shift_left (norm).bit_or (n0.bit_shift_right (0 - norm)), d_cursor, dinv)
								r := r_res.item
								target [target_cursor] := q_res.item
								target_cursor := target_cursor - 1
								n1 := n0
								i := i - 1
							end
							udiv_qrnnd_preinv (q_res, r_res, r, n1.bit_shift_left (norm), d_cursor, dinv)
							r := r_res.item
							target [target_cursor] := q_res.item
							target_cursor := target_cursor - 1
						end
						Result := r.bit_shift_right (norm)
					end
				end
			end
		end

	udiv_qrnnd_preinv (q: CELL [NATURAL_32]; r: CELL [NATURAL_32]; nh: NATURAL_32; nl: NATURAL_32; d: NATURAL_32; di: NATURAL_32)
		local
			n2: NATURAL_32
			n10: NATURAL_32
			nmask: NATURAL_32
			nadj: NATURAL_32
			q1: NATURAL_32
			xh: CELL [NATURAL_32]
			xl: CELL [NATURAL_32]
		do
			create xh.put (0)
			create xl.put (0)
			n2 := nh
			n10 := nl
			nmask := limb_highbit_to_mask (n10)
			nadj := n10 + (nmask.bit_and (d))
			umul_ppmm (xh, xl, di, n2 - nmask)
			add_ssaaaa (xh, xl, xh.item, xl.item, n2, nadj)
			q1 := xh.item.bit_not
			umul_ppmm (xh, xl, q1, d)
			add_ssaaaa (xh, xl, xh.item, xl.item, nh, nl)
			xh.put (xh.item - d)
			r.put (xl.item + d.bit_and (xh.item))
			q.put (xh.item - q1)
		end

	udiv_qrnd_unnorm (q: CELL [NATURAL_32]; r: CELL [NATURAL_32]; n: NATURAL_32; d: NATURAL_32)
		do
			q.put (n // d)
			r.put (n \\ d)
		end

	add_ssaaaa (sh: CELL [NATURAL_32]; sl: CELL [NATURAL_32]; ah: NATURAL_32; al: NATURAL_32; bh: NATURAL_32; bl: NATURAL_32)
		local
			x: NATURAL_32
		do
			x := al + bl
			sh.put (ah + bh + (x < al).to_integer.to_natural_32)
			sl.put (x)
		end

	limb_highbit_to_mask (limb: NATURAL_32): NATURAL_32
		do
			if limb.bit_test (31) then
				Result := Result.bit_not
			end
		end

	mod_1 (op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER; op1_count_a: INTEGER; d_a: NATURAL_32; remainder: CELL [NATURAL_32])
			-- Divides `op1' by `d_a' and places remainder in `remainder'
		require
			op1_count_a >= 0
			d_a /= 0
		local
			i: INTEGER
			n1: NATURAL_32
			n0: NATURAL_32
			r: CELL [NATURAL_32]
			dummy: CELL [NATURAL_32]
			op1_count: INTEGER
			inv: NATURAL_32
			norm: INTEGER
			d: NATURAL_32
		do
			create r.put (0)
			create dummy.put (0)
			d := d_a
			op1_count := op1_count_a
			if op1_count = 0 then
				remainder.put (0)
			else
				if d.bit_test (limb_high_bit) then
					r.put (op1 [op1_offset - 1])
					if r.item >= d then
						r.put (r.item - d)
					end
					op1_count := op1_count - 1
					if op1_count = 0 then
						remainder.put (r.item)
					else
						inv := limb_inverse (d)
						from
							i := op1_count - 1
						until
							i < 0
						loop
							n0 := op1 [op1_offset + i]
							udiv_qrnnd_preinv (dummy, r, r.item, n0, d, inv)
							i := i - 1
						end
						remainder.put (r.item)
					end
				else
					r.put (op1 [op1_offset + op1_count - 1])
					if r.item < d and op1_count - 1 = 0 then
						remainder.put (r.item)
					else
						if r.item < d then
							op1_count := op1_count - 1
						else
							r.put (0)
						end
						norm := leading_zeros (d)
						d := d |<< norm
						n1 := op1 [op1_offset + op1_count - 1]
						r.put ((r.item |<< norm).bit_or (n1 |>> (limb_bits - norm)))
						inv := limb_inverse (d)
						from
							i := op1_count - 2
						until
							i < 0
						loop
							n0 := op1 [op1_offset + i]
							udiv_qrnnd_preinv (dummy, r, r.item, (n1 |<< norm).bit_or (n0 |>> (limb_bits - norm)), d, inv)
							n1 := n0
							i := i - 1
						end
						udiv_qrnnd_preinv (dummy, r, r.item, n1 |<< norm, d, inv)
						remainder.put (r.item |>> norm)
					end
				end
			end
		end

	preinv_divrem_1 (qp: SPECIAL [NATURAL_32]; qp_offset_a: INTEGER; xsize: INTEGER; ap: SPECIAL [NATURAL_32]; ap_offset: INTEGER; size_a: INTEGER; d_unnorm: NATURAL_32; dinv: NATURAL_32; shift: INTEGER): NATURAL_32
		require
			xsize >= 0
			size_a >= 1
			d_unnorm /= 0
		local
			ahigh: NATURAL_32
			qhigh: NATURAL_32
			r: CELL [NATURAL_32]
			q: CELL [NATURAL_32]
			i: INTEGER
			n1: NATURAL_32
			n0: NATURAL_32
			d: NATURAL_32
			qp_offset: INTEGER
			size: INTEGER
			done_integer: BOOLEAN
		do
			create r.put (0)
			create q.put (0)
			qp_offset := qp_offset_a
			size := size_a
			ahigh := ap [ap_offset + size - 1]
			d := d_unnorm |<< shift
			qp_offset := qp_offset + (size + xsize - 1)
			if shift = 0 then
				r.put (ahigh)
				qhigh := (r.item >= d).to_integer.to_natural_32
				if qhigh /= 0 then
					r.put (r.item - d)
				end
				qp [qp_offset] := qhigh
				qp_offset := qp_offset - 1
				size := size - 1
				from
					i := size - 1
				until
					i < 0
				loop
					n0 := ap [ap_offset + i]
					udiv_qrnnd_preinv (q, r, r.item, n0, d, dinv)
					qp [qp_offset] := q.item
					qp_offset := qp_offset - 1
					i := i - 1
				end
				done_integer := True
			else
				r.put (0)
				if ahigh < d_unnorm then
					r.put (ahigh |<< shift)
					qp [qp_offset] := 0
					qp_offset := qp_offset - 1
					size := size - 1
					if size = 0 then
						done_integer := True
					end
				end
				if not done_integer then
					n1 := ap [ap_offset + size - 1]
					r.put (r.item.bit_or (n1 |>> (limb_bits - shift)))
					from
						i := size - 2
					until
						i < 0
					loop
						n0 := ap [ap_offset + i]
						udiv_qrnnd_preinv (q, r, r.item, (n1 |<< shift).bit_or (n0 |>> (limb_bits - shift)), d, dinv)
						qp [qp_offset] := q.item
						qp_offset := qp_offset - 1
						n1 := n0
						i := i - 1
					end
					udiv_qrnnd_preinv (q, r, r.item, n1 |<< shift, d, dinv)
					qp [qp_offset] := q.item
					qp_offset := qp_offset - 1
				end
			end
			from
				i := 0
			until
				i >= xsize
			loop
				udiv_qrnnd_preinv (q, r, r.item, 0, d, dinv)
				qp [qp_offset] := q.item
				qp_offset := qp_offset - 1
				i := i + 1
			end
			Result := r.item |>> shift
		end

	sb_divrem_mn (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset_a: INTEGER_32; op1_count: INTEGER_32; op2: SPECIAL [NATURAL_32]; op2_offset: INTEGER_32; op2_count: INTEGER_32): NATURAL_32
			-- Base case division
		require
			op2_count > 2
			op1_count >= op2_count
			op2 [op2_offset + op2_count - 1].bit_test (limb_high_bit)
		local
			most_significant_q_limb: NATURAL_32
			qn: INTEGER_32
			i: INTEGER_32
			dx: NATURAL_32
			d1: NATURAL_32
			n0: NATURAL_32
			dxinv: NATURAL_32
			junk: NATURAL_32
			q: CELL [NATURAL_32]
			nx: NATURAL_32
			cy_limb: NATURAL_32
			rx: NATURAL_32
			r1: CELL [NATURAL_32]
			r0: NATURAL_32
			p1: CELL [NATURAL_32]
			p0: CELL [NATURAL_32]
			cy1: NATURAL_32
			cy2: NATURAL_32
			op1_offset: INTEGER
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			create q.put (0)
			create r1.put (0)
			create p1.put (0)
			create p0.put (0)
			op1_offset := op1_offset_a
			qn := op1_count - op2_count
			op1_offset := op1_offset + qn
			dx := op2 [op2_offset + op2_count - 1]
			d1 := op2 [op2_offset + op2_count - 2]
			n0 := op1 [op1_offset + op2_count - 1]
			if n0 >= dx then
				if n0 > dx or cmp (op1, op1_offset, op2, op2_offset, op2_count - 1) >= 0 then
					sub_n (op1, op1_offset, op1, op1_offset, op2, op2_offset, op2_count, carry)
					junk := carry.item
					most_significant_q_limb := 1
				end
			end
			dxinv := limb_inverse (dx)
			from
				i := qn - 1
			until
				i < 0
			loop
				nx := op1 [op1_offset + op2_count - 1]
				op1_offset := op1_offset - 1
				if nx = dx then
					q.put (0xffffffff)
					submul_1 (op1, op1_offset, op2, op2_offset, op2_count, q.item, carry)
					cy_limb := carry.item
					if nx /= cy_limb then
						add_n (op1, op1_offset, op1, op1_offset, op2, op2_offset, op2_count, carry)
						junk := carry.item
						q.put (q.item - 1)
					end
					target [target_offset + i] := q.item
				else
					udiv_qrnnd_preinv (q, r1, nx, op1 [op1_offset + op2_count - 1], dx, dxinv)
					umul_ppmm (p1, p0, d1, q.item)
					r0 := op1 [op1_offset + op2_count - 2]
					rx := 0
					if r1.item < p1.item or (r1.item = p1.item and r0 < p0.item) then
						p1.put (p1.item - (p0.item < d1).to_integer.to_natural_32)
						p0.put (p0.item - d1)
						q.put (q.item - 1)
						r1.put (r1.item + dx)
						rx := (r1.item < dx).to_integer.to_natural_32
					end
					p1.put (p1.item + (r0 < p0.item).to_integer.to_natural_32)
					rx := rx - (r1.item < p1.item).to_integer.to_natural_32
					r1.put (r1.item - p1.item)
					r0 := r0 - p0.item
					submul_1 (op1, op1_offset, op2, op2_offset, op2_count - 2, q.item, carry)
					cy_limb := carry.item
					cy1 := (r0 < cy_limb).to_integer.to_natural_32
					r0 := r0 - cy_limb
					cy2 := (r1.item < cy1).to_integer.to_natural_32
					r1.put (r1.item - cy1)
					op1 [op1_offset + op2_count - 1] := r1.item
					op1 [op1_offset + op2_count - 2] := r0
					if cy2 /= rx then
						add_n (op1, op1_offset, op1, op1_offset, op2, op2_offset, op2_count, carry)
						junk := carry.item
						q.put (q.item - 1)
					end
					target [target_offset + i] := q.item
				end
				i := i - 1
			end
			Result := most_significant_q_limb
		end

	tdiv_qr (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32)
		require
			denominator_count >= 0
			numerator_count >= 0
			denominator_count = 0 or denominator [denominator_offset + denominator_count - 1] /= 0
		do
			inspect denominator_count
			when 0 then
				(create {DIVIDE_BY_ZERO}).raise
			when 1 then
				remainder [remainder_offset] := divrem_1 (target, target_offset, numerator, numerator_offset, numerator_count, denominator [denominator_offset])
			when 2 then
				tdiv_qr_two_case (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count)
			else
				tdiv_qr_large_case (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count)
			end
		end

	tdiv_qr_large_numerator (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count_a: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32; adjust: INTEGER_32)
		local
			d2p: SPECIAL [NATURAL_32]
			d2p_offset: INTEGER_32
			cy: NATURAL_32
			cnt: INTEGER_32
			n2p: SPECIAL [NATURAL_32]
			n2p_offset: INTEGER_32
			numerator_count: INTEGER_32
			junk: NATURAL_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			numerator_count := numerator_count_a
			target [target_offset + numerator_count - denominator_count] := 0
			if not denominator [denominator_offset + denominator_count - 1].bit_test (31) then
				cnt := leading_zeros (denominator [denominator_offset + denominator_count - 1])
				create d2p.make_filled (0, denominator_count)
				d2p_offset := 0
				lshift (d2p, d2p_offset, denominator, denominator_offset, denominator_count, cnt, carry)
				junk := carry.item
				create n2p.make_filled (0, numerator_count + 1)
				n2p_offset := 0
				lshift (n2p, n2p_offset, numerator, numerator_offset, numerator_count, cnt, carry)
				cy := carry.item
				n2p [n2p_offset + numerator_count] := cy
				numerator_count := numerator_count + adjust
			else
				cnt := 0
				d2p := denominator
				d2p_offset := denominator_offset
				create n2p.make_filled (0, numerator_count + 1)
				n2p_offset := 0
				n2p.copy_data (numerator, numerator_offset, n2p_offset, numerator_count)
				n2p [n2p_offset + numerator_count] := 0
				numerator_count := numerator_count + adjust
			end
			if denominator_count < 3 * 32 then
				junk := sb_divrem_mn (target, target_offset, n2p, n2p_offset, numerator_count, d2p, d2p_offset, denominator_count)
			else
				tdiv_qr_large_denominator (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count, n2p, n2p_offset, d2p, d2p_offset, numerator_count)
			end
			if cnt /= 0 then
				rshift (remainder, remainder_offset, n2p, n2p_offset, denominator_count, cnt, carry)
				junk := carry.item
			else
				remainder.copy_data (n2p, n2p_offset, remainder_offset, denominator_count)
			end
		end

	tdiv_qr_large_denominator (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32; n2p: SPECIAL [NATURAL_32]; n2p_offset_a: INTEGER_32; d2p: SPECIAL [NATURAL_32]; d2p_offset_a: INTEGER_32; nn_a: INTEGER_32)
		local
			q2p: SPECIAL [NATURAL_32]
			q2p_offset: INTEGER_32
			q1: NATURAL_32
			junk: NATURAL_32
			n2p_offset: INTEGER_32
			d2p_offset: INTEGER_32
			nn: INTEGER_32
		do
			nn := nn_a
			n2p_offset := n2p_offset_a
			d2p_offset := d2p_offset_a
			q2p := target
			q2p_offset := target_offset + nn - denominator_count
			n2p_offset := n2p_offset + nn - denominator_count
			from
			until
				nn < 2 * denominator_count
			loop
				q2p_offset := q2p_offset - denominator_count
				n2p_offset := n2p_offset - denominator_count
				junk := dc_divrem_n (q2p, q2p_offset, n2p, n2p_offset, d2p, d2p_offset, denominator_count)
				nn := nn - denominator_count
			end
			if nn /= denominator_count then
				n2p_offset := n2p_offset - nn - denominator_count
				q1 := target [target_offset + nn - denominator_count]
				tdiv_qr (target, target_offset, n2p, n2p_offset, n2p, n2p_offset, nn, d2p, d2p_offset, denominator_count)
				target [target_offset + nn - denominator_count] := q1
			end
		end

	tdiv_qr_large_case (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32)
		local
			adjust: INTEGER_32
		do
			adjust := (numerator [numerator_offset + numerator_count - 1] >= denominator [denominator_offset + denominator_count - 1]).to_integer
			if numerator_count + adjust >= 2 * denominator_count then
				tdiv_qr_large_numerator (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count, adjust)
			else
				tdiv_qr_small_numerator (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count, adjust)
			end
		end

	tdiv_qr_small_numerator (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32; adjust: INTEGER_32)
		local
			qn: INTEGER_32
		do
			qn := numerator_count - denominator_count
			target [target_offset + qn] := 0
			qn := qn + adjust
			if qn = 0 then
				remainder.copy_data (numerator, numerator_offset, remainder_offset, denominator_count)
			else
				tdiv_qr_non_zero_quotient (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count, adjust, qn)
			end
		end

	tdiv_qr_non_zero_quotient (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32; adjust: INTEGER_32; qn: INTEGER_32)
		local
			d2p: SPECIAL [NATURAL_32]
			d2p_offset: INTEGER_32
			cy: NATURAL_32
			cnt: INTEGER_32
			n2p: SPECIAL [NATURAL_32]
			n2p_offset: INTEGER_32
			in: INTEGER_32
			rn: INTEGER_32
			junk: NATURAL_32
			dl: NATURAL_32
			x: NATURAL_32
			h: CELL [NATURAL_32]
			dummy: CELL [NATURAL_32]
			cy1: NATURAL_32
			cy2: NATURAL_32
			quotient_too_large: NATURAL_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			in := denominator_count - qn
			if not denominator [denominator_offset + denominator_count - 1].bit_test (limb_high_bit) then
				cnt := leading_zeros (denominator [denominator_offset + denominator_count - 1])
				create d2p.make_filled (0, qn)
				d2p_offset := 0
				lshift (d2p, d2p_offset, denominator, denominator_offset + in, qn, cnt, carry)
				junk := carry.item
				d2p [d2p_offset] := d2p [d2p_offset].bit_or ((denominator [denominator_offset + in - 1]) |>> (limb_bits - cnt))
				create n2p.make_filled (0, 2 * qn + 1)
				n2p_offset := 0
				lshift (n2p, n2p_offset, numerator, numerator_offset + numerator_count - 2 * qn, 2 * qn, cnt, carry)
				cy := carry.item
				if adjust /= 0 then
					n2p [n2p_offset + 2 * qn] := cy
					n2p_offset := n2p_offset + 1
				else
					n2p [n2p_offset] := n2p [n2p_offset].bit_or ((numerator [numerator_offset + numerator_count - 2 * qn - 1]) |>> (limb_bits - cnt))
				end
			else
				cnt := 0
				d2p := denominator
				d2p_offset := denominator_offset + in
				create n2p.make_filled (0, 2 * qn + 1)
				n2p_offset := 0
				n2p.copy_data (numerator, numerator_offset + numerator_count - 2 * qn, n2p_offset, 2 * qn)
				if adjust /= 0 then
					n2p [n2p_offset + 2 * qn] := 0
					n2p_offset := n2p_offset + 1
				end
			end
			tdiv_qr_internal_divide (target, target_offset, n2p, n2p_offset, d2p, d2p_offset, qn)
			rn := qn
			create h.put (0)
			create dummy.put (0)
			if in - 2 < 0 then
				dl := 0
			else
				dl := denominator [denominator_offset + in - 2]
			end
			x := (denominator [denominator_offset + in - 1] |<< cnt).bit_or ((dl |>> 1) |>> (cnt.bit_not \\ limb_bits))
			umul_ppmm (h, dummy, x, target [target_offset + qn - 1])
			if n2p [n2p_offset + qn - 1] < h.item then
				decr_u (target, target_offset, 1)
				add_n (n2p, n2p_offset, n2p, n2p_offset, d2p, d2p_offset, qn, carry)
				cy := carry.item
				if cy /= 0 then
					n2p [n2p_offset + qn] := cy
					rn := rn + 1
				end
			end
			if cnt /= 0 then
				lshift (n2p, n2p_offset, n2p, n2p_offset, rn, limb_bits - cnt, carry)
				cy1 := carry.item
				n2p [n2p_offset] := n2p [n2p_offset].bit_or (numerator [numerator_offset + in - 1].bit_and ((0xffffffff).to_natural_32 |>> cnt))
				submul_1 (n2p, n2p_offset, target, target_offset, qn, denominator [denominator_offset + in - 1].bit_and ((0xffffffff).to_natural_32 |>> cnt), carry)
				cy2 := carry.item
				if qn /= rn then
					n2p [n2p_offset + qn] := n2p [n2p_offset + qn] - cy2
				else
					n2p [n2p_offset + qn] := cy1 - cy2
					quotient_too_large := (cy1 < cy2).to_integer.to_natural_32
					rn := rn + 1
				end
				in := in - 1
			end
			tdiv_qr_shift_result (target, target_offset, remainder, remainder_offset, numerator, numerator_offset, numerator_count, denominator, denominator_offset, denominator_count, adjust, qn, n2p, n2p_offset, d2p, d2p_offset, rn, in, cnt, quotient_too_large)
		end

	tdiv_qr_internal_divide (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; qn: INTEGER_32)
		local
			junk: NATURAL_32
		do
			if qn = 1 then
				tdiv_qr_internal_divide_1 (target, target_offset, numerator, numerator_offset, denominator, denominator_offset)
			elseif qn = 2 then
				junk := divrem_2 (target, target_offset, numerator, numerator_offset, 4, denominator, denominator_offset)
			elseif qn < 3 * 32 then
				junk := sb_divrem_mn (target, target_offset, numerator, numerator_offset, 2 * qn, denominator, denominator_offset, qn)
			else
				junk := dc_divrem_n (target, target_offset, numerator, numerator_offset, denominator, denominator_offset, qn)
			end
		end

	tdiv_qr_internal_divide_1 (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER)
		local
			q0: TUPLE [q0: NATURAL_32]
			r0: TUPLE [r0: NATURAL_32]
		do
			create q0
			create r0
			udiv_qrnnd (q0, r0, numerator [numerator_offset + 1], numerator [numerator_offset], denominator [denominator_offset])
			numerator [numerator_offset] := r0.r0
			target [target_offset] := q0.q0
		end

	tdiv_qr_shift_result (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32; adjust: INTEGER_32; qn: INTEGER_32; n2p: SPECIAL [NATURAL_32]; n2p_offset: INTEGER_32; d2p: SPECIAL [NATURAL_32]; d2p_offset: INTEGER_32; rn_a: INTEGER_32; in: INTEGER_32; cnt: INTEGER_32; quotient_too_large_a: NATURAL_32)
		local
			tp: SPECIAL [NATURAL_32]
			tp_offset: INTEGER_32
			junk: NATURAL_32
			goto: BOOLEAN
			cy: NATURAL_32
			rn: INTEGER_32
			quotient_too_large: NATURAL_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			quotient_too_large := quotient_too_large_a
			rn := rn_a
			create tp.make_filled (0, denominator_count)
			tp_offset := 0
			if in < qn and in = 0 then
				if in = 0 then
					remainder.copy_data (n2p, n2p_offset, remainder_offset, rn)
					goto := True
				else
					mul (tp, tp_offset, target, target_offset, qn, denominator, denominator_offset, in, carry)
					junk := carry.item
				end
			else
				mul (tp, tp_offset, denominator, denominator_offset, in, target, target_offset, qn, carry)
				junk := carry.item
			end
			if not goto then
				sub (n2p, n2p_offset, n2p, n2p_offset, rn, tp, tp_offset + in, qn, carry)
				cy := carry.item
				remainder.copy_data (n2p, n2p_offset, remainder_offset + in, denominator_count - in)
				quotient_too_large := quotient_too_large.bit_or (cy)
				sub_n (remainder, remainder_offset, numerator, numerator_offset, tp, tp_offset, in, carry)
				cy := carry.item
				sub_1 (remainder, remainder_offset + in, remainder, remainder_offset + in, rn, cy, carry)
				cy := carry.item
				quotient_too_large := quotient_too_large.bit_or (cy)
			end
			if quotient_too_large /= 0 then
				decr_u (target, target_offset, 1)
				add_n (remainder, remainder_offset, remainder, remainder_offset, denominator, denominator_offset, denominator_count, carry)
				junk := carry.item
			end
		end

	tdiv_qr_two_case (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; remainder: SPECIAL [NATURAL_32]; remainder_offset: INTEGER_32; numerator: SPECIAL [NATURAL_32]; numerator_offset: INTEGER_32; numerator_count: INTEGER_32; denominator: SPECIAL [NATURAL_32]; denominator_offset: INTEGER_32; denominator_count: INTEGER_32)
		local
			d2p: SPECIAL [NATURAL_32]
			d2p_offset: INTEGER_32
			qhl: NATURAL_32
			cy: NATURAL_32
			cnt: INTEGER_32
			dtmp: SPECIAL [NATURAL_32]
			n2p: SPECIAL [NATURAL_32]
			n2p_offset: INTEGER_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			create dtmp.make_filled (0, 2)
			if not denominator [denominator_offset + 1].bit_test (31) then
				cnt := leading_zeros (denominator [denominator_offset + 1])
				d2p := dtmp
				d2p [d2p_offset + 1] := (denominator [denominator_offset + 1] |<< cnt).bit_or (denominator [denominator_offset] |>> (limb_bits - cnt))
				d2p [d2p_offset] := denominator [denominator_offset] |<< cnt
				create n2p.make_filled (0, numerator_count + 1)
				lshift (n2p, 0, numerator, numerator_offset, numerator_count, cnt, carry)
				cy := carry.item
				n2p [numerator_count] := cy
				qhl := divrem_2 (target, target_offset, n2p, n2p_offset, numerator_count + (cy /= 0).to_integer, d2p, d2p_offset)
				if cy = 0 then
					target [target_offset + numerator_count - 2] := qhl
				end
				remainder [remainder_offset] := (n2p [0] |>> cnt).bit_or (n2p [1] |<< (limb_bits - cnt))
				remainder [remainder_offset + 1] := n2p [1] |>> cnt
			else
				d2p := denominator
				d2p_offset := denominator_offset
				create n2p.make_filled (0, numerator_count)
				n2p.copy_data (numerator, numerator_offset, 0, numerator_count)
				qhl := divrem_2 (target, target_offset, n2p, 0, numerator_count, d2p, d2p_offset)
				target [target_offset + numerator_count - 2] := qhl
				remainder [remainder_offset] := n2p [0]
				remainder [remainder_offset + 1] := n2p [1]
			end
		end
end
