On Sun, 19 Oct 2008 10:07:34 -0500, Sebastian Hungerecker wrote:

> Matthew Moss wrote:
>> ## Long Division (#180)
>>
>> Your task this week is to perform and display long division.
> 
> This isn't thoroughly tested but it seems to work. It supports
> specifying a base and it can display the result either as
> integer+remainder or as a decimal. There's no option to limit the digits
> as I didn't see the point. If the number is periodic, it draws a
> vinculum above the apropriate digits. Usage: long_divide dividend
> divisor [--base=BASE] [--remainder] BASE is the base as a decimal number
> (both dividend and divisor are specified as BASE)
> If --remainder is specified, it will print the integer part of the
> division and the remainder, instead of printing the result as a decimal.
> If the division has no remainder, there is no difference.
> 
> The code can be used from irb (or another script, if you should want to
> do that for some reason), by requireing it and then using the divide
> method. Here's the code:
> http://pastie.org/295741
> 
> Some sample output from irb:
>>> divide(1,3)
>     _
>   0.3
>  +-
> 3|1
>   0
>   -
>   10
>    9
>   --
>    1
> => nil
>>> divide(1,3,2)
>      __
>    0.01
>   +-
> 11|1
>    0
>    -
>    10
>     0
>    --
>    100
>     11
>    ---
>      1
> => nil
>>> divide(10,7)
>      ______
>    1.428571
>  +--
> 7|10
>    7
>   --
>    30
>    28
>    --
>     20
>     14
>     --
>      60
>      56
>      --
>       40
>       35
>       --
>        50
>        49
>        --
>         10
>          7
>         --
>          3
> => nil
>>> divide(1,6)
>      _
>   0.16
>  +-
> 6|1
>   0
>   -
>   10
>    6
>   --
>    40
>    36
>    --
>     4
>>> divide(1,6,10,false)
>   0 R1
>  +-
> 6|1
>   0
>   -
>   1
> => nil

I'm posting Sebastian's solution to the newsgroup, because I don't know
long pastie will keep the code around. Please don't use pastebins with 
ruby-talk -- the code may disappear while the message sticks around, then
we can't see your ingenious solutions or your questions.

#!/usr/bin/ruby

module LongDivision
  module_function
  def divide(dividend, divisor, base=10, decimal=true)
    result = ""
    division = " "*divisor.to_s(base).length
    division << "+".ljust(dividend.to_s(base).length + 1,"-") << "\n"
    division << "#{divisor.to_s(base)}|#{dividend.to_s(base)}"
    indent = divisor.to_s(base).length + 1
    digits = dividend.to_s(base).chars.map {|d| d.to_i(base) }
    quotient = 0
    remainder = 0
    while remainder < divisor && digits.size > 0
      remainder = remainder * base + digits.shift
      indent += 1
    end

    digits << nil
    digits.each do |digit|
      quotient = remainder / divisor
      result << quotient.to_s(base)
      prod = (quotient * divisor).to_s(base)
      division << "\n" << prod.rjust(indent) << "\n"
      division << ("-" * remainder.to_s(base).length).rjust(indent) << "\n"
      remainder %= divisor
      remstring = ""
      if digit
        remstring = "0" if remainder == 0
        remainder = remainder * base + digit
        indent += 1
      end
      remstring << remainder.to_s(base)
      division << remstring.rjust(indent)
    end
   
    if remainder == 0
      puts result.rjust(division.lines.first.length-1), division
    elsif decimal
      rem_positions = {}
      dec_result = ""
      periodicity = 0
      while remainder > 0
        if rem_positions[remainder]
          periodicity = rem_positions.size - rem_positions[remainder]
          break
        end
        rem_positions[remainder] = rem_positions.size
        division << "0\n"
        indent += 1
        remainder *= base
        quotient = remainder / divisor
        dec_result << quotient.to_s(base)
        prod = (quotient * divisor).to_s(base)
        division <<  prod.rjust(indent) << "\n"
        division << ("-" * remainder.to_s(base).length).rjust(indent) << "\n"
        remainder %= divisor
        division << remainder.to_s(base).rjust(indent)
      end
      result = "#{result.rjust(division.lines.first.length-1)}.#{dec_result}"
      if periodicity > 0
        puts ("_"*periodicity).rjust(result.size)
      end
      puts result, division
    else
      puts "#{result.rjust(division.lines.first.length-1)} R#{remainder.to_s(base)}", division
    end
  end
end

if $0 == __FILE__
  base = ARGV.find {|arg| arg =~ /^--base/}
  if base
    base = base.split("=",2).last.to_i(10)
  else
    base = 10
  end

  dividend = ARGV.shift.to_i(base)
  divisor = ARGV.shift.to_i(base)
  decimal = !ARGV.include?("--remainder")
  LongDivision.divide(dividend, divisor, base, decimal)
end




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