0

I need another set of eyes to tell me what is wrong with my Eiffel implementation of Burnikel and Ziegler's division, specifically "Algorithm 2 - 3n/2n". The Eiffel feature is shown below. The type "like Current" is an ARRAYED_LIST [NATURAL_8]. In other words, the implementation uses digits (i.e. limbs) containing 8-bit values, so numbers are in base-256. A manual trace of a failing call follows. (Sorry the arguments are so large, but I cannot reproduce the error with shorter values.) Execution follows step 3b in this case.

Here's the problem. The algorithm seems to be fine to Step 5, where the remainder "r" ends up with more digits then the divisor. I believe the error is in step 3b, perhaps with the call to feature `ones' which is "supposed" to supply a value that is "Beta^n - 1". (Maybe I do not understand B&Z's "Beta^n" notation.

Here is the Eiffel code:

three_by_two_divide (a, a3, b: like Current): TUPLE [quot, rem: like Current]
        -- Called by `two_by_one_divide'.  It has similar structure as
        -- `div_three_halves_by_two_halfs', but the arguments to this
        -- function have type {JJ_BIG_NATURAL} instead of like `digit'.
        -- See Burnikel & Zieler, "Fast Recursive Division", pp 4-8,
        -- Algorithm 2.
    require
        n_not_odd: b.count >= div_limit and b.count \\ 2 = 0
        b_has_2n_digits: b.count = a3.count * 2
        a_has_2n_digits: a.count = a3.count * 2
    local
        n: INTEGER
        a1, a2: like Current
        b1, b2: like Current
        tup: TUPLE [quot, rem: like Current]
        q, q1, q2, r, r1: like Current
        c, d: like Current
    do
        n := b.count // 2
            -- 1) Split `a'
        a1 := new_sub_number (n + 1, a.count, a)
        a2 := new_sub_number (1, n.max (1), a)
            -- 2) Split `b'.
        b1 := new_sub_number (n + 1, b.count, b)
        b2 := new_sub_number (1, n.max (1), b)
            -- 3) Distinguish cases.
        if a1 < b1 then
                -- 3a) compute Q = floor ([A1,A2] / B1 with remainder.
            if b1.count < div_limit then
                tup := school_divide (a, b1)
            else
                tup := two_by_one_divide (a, b1)
            end
            q := tup.quot
            r1 := tup.rem
        else
                -- 3b) Q = beta^n - 1 and ...
            q := ones (n)
                -- ... R1 = [A1,A2] - [B1,0] + [0,B1] = [A1,A2] - QB1.
            r1 := a + b1
            if n > 1 then
                b1.shift_left (n)
            else
                b1.bit_shift_left (zero_digit.bit_count // 2)
            end
            r1.subtract (b1)
        end
            -- 4) D = Q * B2
        d := q * b2
            -- 5) R1 * B^n + A3 - D.  (The paper says "a4".)
        r1.shift_left (n)
        r := r1 + a3 - d
            -- 6) As long as R < 0, repeat
        from
        until not r.is_negative
        loop
            r := r + b
            q.decrement
        end
        check
            remainder_small_enough: r.count <= b.count
                -- because remainder must be less than divisor.
        end
        Result := [q, r]
    ensure
   --   n_digit_remainder: Result.rem.count = b.count // 2
        quotient_has_correct_count: Result.quot.count <= b.count // 2
    end

In the trace, the arrow points to a line I believe is bad, but I don't know what to do with it. Here is the trace:

three_by_two_divide (a = [227,26,41,95,169,93,135,110], 
                     a3 = [92,164,19,39],
                     b =  [161,167,158,41,164,0,0,0]) 

    n := b.count // 2 = 4
        -- 1) Split `a'.
    a1 := new_sub_number (n + 1, a.count, a) = [227,26,41,95]
    a2 := new_sub_number (1, n.max (1), a) = [169,93,135,110]
        -- 2) Split `b'.
    b1 := new_sub_number (n + 1, b.count, b) = [161,167,158,41]
    b2 := new_sub_number (1, n.max (1), b) = [164,0,0,0]
        -- 3b) Q = beta^n -1 and ...
--> q := ones (4) = [255,255,255,255]          <-- Is this the error?
        -- ... R1 = [A1,A2] - [B1,0] + [0,B1].
    r1 := a + b1 = [227,26,41,96,75,5,37,151]
    b1.shift_left (n) = [161,167,158,41,0,0,0,0]                        
    r1.subtract (b1) = [65,114,139,55,75,5,37,151]
    d := q * b2 = [163,255,255,255,92,0,0,0]
    r1.shift_left (n) = [227,25,135,184,172,220,37,151,0,0,0,0]   -- too big!
    r := r1 + a3 - d -= [227,25,135,184,8,220,37,152,0,164,19,39] -- too big!

I know this is long, but any help is appreciated.

jjj
  • 23
  • 8

1 Answers1

0

I would suggest to check that r1 = [65,114,139,55,75,5,37,151] is still the same before doing r1.shift_left (n). There are two options:

  1. d := q * b2 affects r1 while it should not. Most probably there is some aliasing, i.e. r1 is aliased with some other variable that is updated and this aliasing should be removed.
  2. r1 is still the same after d := q * b2. The issue is with shift_left that fails to (re)initialize some data or uses global data that it should not.
Alexander Kogtenkov
  • 5,770
  • 1
  • 27
  • 35
  • Thanks Alexander, no aliasing and no global data. I think I have fixed this problem by avoiding the call to `ones'. Burnikel & Ziegler say for division of A by B, "let A < Bβ^n". I had missed that precondition. The solution is: if A >= Bβ^n, get a new_a := A - B and remember the quotient starts with a 1. At this point, A is less than B, so proceed as B&Z say. I have another problem though which I will post in a new question. Thanks. – jjj Apr 27 '17 at 03:46
  • I do not really see how shifting `[65,114,139,55,75,5,37,151]` left by 4 digits with `r1.shift_left (n)` gives `[227,25,135,184,172,220,37,151,0,0,0,0]`. It would help understanding the implementation if you can explain such behavior. – Alexander Kogtenkov Apr 28 '17 at 06:44