On Fri, 17 Oct 2008 08:57:01 -0500, Matthew Moss wrote:

> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
> 
> The three rules of Ruby Quiz 2:
> 
> 1.  Please do not post any solutions or spoiler discussion for this quiz
> until 48 hours have passed from the time on this message.
> 
> 2.  Support Ruby Quiz 2 by submitting ideas as often as you can! (A
> permanent, new website is in the works for Ruby Quiz 2. Until then,
> please visit the temporary website at
> 
>     <http://splatbang.com/rubyquiz/>.
> 
> 3.  Enjoy!
> 
> Suggestion:  A [QUIZ] in the subject of emails about the problem helps
> everyone on Ruby Talk follow the discussion.  Please reply to the
> original quiz message, if you can.
> 
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
> 
> ## Long Division (#180)
> 
> Your task this week is to perform and display long division.
> 
> Your program should take two arguments: the dividend and the divisor.
> Your output should display the long division needed to determine the
> quotient and remainder (if it exists). For example, if I run your
> program like so:
> 
>      $ ruby long_division.rb 11 4096
> 
> Your program's output should be:
> 
>          372 R4
>        +----
>      11|4096
>         33
>         --
>          79
>          77
>          --
>           26
>           22
>           --
>            4
> 
> If there is no remainder, do not display anything after the quotient;
> that is, do not display R0. As an alternative to the remainder, you may
> instead calculate the decimal fraction out to N digits (e.g. use
> command-line option --digits=N or similar to switch to decimal fraction
> output).



class Integer
  def longdiv divisor
    begin
      # do math
      products=[]
      dividends=[self] #intermediate dividends -- the next number we'll divide
      exps=[]
      dividend=self
      quotient=0
      while dividend>=divisor
        Math.log10(dividend).ceil.downto(0) do |exp|
          magnitude=10**exp
          trydiv,rest=dividend.divmod(magnitude)
          if trydiv>=divisor
            exps << exp
            dividends[-1]=trydiv
            quotient_digit,remainder=trydiv.divmod(divisor)
            products << quotient_digit*divisor
            quotient+=quotient_digit*magnitude
            dividend=(remainder*magnitude+rest)
            dividends << remainder
            break
          end
        end
      end

    ensure
      #danger of infinite loops, so if I have
      #to hit ^C to debug one, I want to be sure to print
      #what I've got so I can debug

      fmtwidth=self.to_s.size+divisor.to_s.size+1
      exps << 0

      printf "%#{fmtwidth}d",quotient
      print " R#{dividends.last}" if dividends.last > 0
      puts ""
      puts " "*divisor.to_s.size+"+"+"-"*self.to_s.size
      puts divisor.to_s+"|"+self.to_s
      i=0
      while i<products.size
        printf "%#{fmtwidth-exps[i]}d\n",products[i]
        printf "%#{fmtwidth-exps[i]}s\n","-"*products[i].to_s.size
        i+=1
        printf "%#{fmtwidth-exps[i]}d\n",dividends[i]
      end
      puts
    end

    [quotient,dividend]
  end
end

require 'test/unit'
require 'stringio'

class TestLongDiv < Test::Unit::TestCase
  def test_division
    assert_equal [372,4],4096.longdiv(11)
    assert_equal [302,4],(4096-770).longdiv(11)
    assert_equal [0,100],100.longdiv(1000)
    
    #the following cases showed up as problematic ones when I ran
    #the big loop that follows
    assert_equal 2205.divmod(10),2205.longdiv(10)
    assert_equal 2442.divmod(2),2442.longdiv(2)

    #are there problems I didn't think of?
    1000.times do
      dividend=rand(10000)
      divisor=rand(50)+1
      printf "%d / %d\n", dividend, divisor
      assert_equal dividend.divmod(divisor),dividend.longdiv(divisor)
    end
  end


  def test_output_format
    oldstdout=$stdout
    begin
      newstdout=StringIO.new
      $stdout=newstdout
expected=<<OUTPUT
    372 R4
  +----
11|4096
   33
   --
    79
    77
    --
     26
     22
     --
      4

OUTPUT
      4096.longdiv(11)
      $stdout=oldstdout
      assert_equal expected,newstdout.string
    ensure
      $stdout=oldstdout
    end
  end
end

-- 
Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/