comp.lang.ada
 help / color / mirror / Atom feed
From: ka@sorry.no.email (Kenneth Almquist)
Subject: Re: implementing software unsigned divide
Date: 13 May 2001 19:17:22 -0400
Date: 2001-05-13T19:17:22-04:00	[thread overview]
Message-ID: <9dn4m2$qvj$1@shell.monmouth.com> (raw)
In-Reply-To: 3AF985BD.BC0E1C12@averstar.com

Tucker Taft <stt@averstar.com> wrote:
> A more general solution, I believe, is to (logical) shift both the
> dividend and divisor right 1 bit, do the divide, and then adjust the
> quotient up or down by 1 to get the remainder to be >= 0 and less
> than the divisor. (Obviously you need to first check for the special
> case when the divisor is <= 1!)

The adjustment may be more than one.  For example,

	2**31 / 3 = 715_827_882
	((2**31)/2) / (3/2) = 2**30 / 1 = 1_073_741_824

The logical shift does work for the case where only the dividend has
the high order bit set:


function To_Signed is new Unchecked_Conversion(Unsigned_32, Long_Integer);
function To_Unsigned is new Unchecked_Conversion(Long_Integer, Unsigned_32);


function "/"(Left, Right : Unsigned_32) return Unsigned_32 is
begin
    if To_Signed(Left or Right) >= 0 then
        -- Neither operand has the high order bit set, so we can
        -- use signed division.
        return To_Unsigned(To_Signed(Left) / To_Signed(Right));
    elsif To_Signed(Right) < 0 then
        -- The high order bit of right is set, so that left must be
        -- less than 2 * right.  Therefore, the result is either
        -- zero or one.
        return Boolean'pos(Left >= Right);
    else -- left has high order bit set, right does not.
        declare
            Guess : Unsigned_32 :=
                      To_Unsigned(To_Signed(Left / 2) / To_Signed(Right)) * 2;
        begin
            -- Guess is either be the correct answer or one less than the
            -- correct answer.  In what follows, "/" is mathematically
            -- exact division, "floor(x)" is the largest integer no larger
            -- than x, and "floor2(x)" is the largest integral multiple of 2
            -- no larger than x.  Our goal is to compute floor(left / right).
            --   guess = floor(floor(left/2) / right) * 2
            --         = floor((left/2) / right) * 2
            --         = floor2(left / right)
            -- floor(left / right) - floor2(left / right) = 0 or 1.
            -- Therefore, guess may be one too small, and we check for that
            -- by multiplying.
            if Left - Guess * Right >= Right then
                Guess := Guess + 1;
            end if;
            return Guess;
        end;
    end if;
end "/";


Depending on how expensive multiplication is on the processor in
question, it might be faster to code the computation of the first
bit of the quotient by hand, and use the signed divide instruction
to get the remaining bits.  The basic idea is:

    else -- left has high order bit set, right does not.
        declare
            Left_Shifted : Unsigned_32;
            Shift : Natural;
        begin
            if Right = 0 then
                raise Constraint_Error;    -- division by zero
            end if;
            Shift := 0;
            Left_Shifted := Left / 2;
            while Left_Shifted >= Right loop
                Left_Shifted := Left_Shifted / 2;
                Shift := Shift + 1;
            end loop;
            return Shift_Left(1, Shift) +
                To_Unsigned(To_Signed(Left - Shift_Left(Right, Shift))
                            / To_Signed(Right));
        end;
    end if;

The while loop can execute up to 31 times in this code, so you probably
don't want to use this code as is.  You could, for example, start out
by comparing right to 2**16 or comparing left/2**16 to right.
				Kenneth Almquist



      parent reply	other threads:[~2001-05-13 23:17 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-05-07 21:42 implementing software unsigned divide Stephen Leake
2001-05-08  6:04 ` Jacob Sparre Andersen
2001-05-08  7:44 ` Tarjei T. Jensen
2001-05-08 13:18 ` Ted Dennison
2001-05-08 15:24 ` Tucker Taft
2001-05-08 21:20   ` Stephen Leake
2001-05-09 18:00     ` Tucker Taft
2001-05-10 15:54       ` Stephen Leake
2001-05-13 23:17       ` Kenneth Almquist [this message]
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox