challenge 割り算の筆算

整数 n, m を与えれば、 n ÷ m の筆算を出力するような
プロシージャ(関数)を創ってください。

ウィンドウに描画するもよし、
コンソールに出力するもよし、です。

Posted feedbacks - Flatten

Nested Hidden
gauche 0.8.13です。
商の0になる桁の計算過程表示が冗長ですが・・・

gosh> (warizan 54321 5)
  10864 ... 1
  -----
5)54321
  5
  -----
   4
   0
  -----
   43
   40
  -----
    32
    30
  -----
     21
     20
  -----
      1
#<undef>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
(define (warizan n m)
  (define (printf format-str . data)
    (display (apply format format-str data)))

  (define (width data)
    (string-length (format "~a" data)))

  (define (num-at n scale)
    (remainder (quotient n scale) 10))

  (define (div-num x scale)
    (let ((q (quotient x scale)))
      (string-append
       (make-string (- (+ (width n) (width m) 2)
               (width q)
               (width scale))
            #\space)
       (number->string q))))

  (define (div-line)
    (string-append
     (make-string (+ (width m) 1) #\space)
     (make-string (width n) #\-)))

  (let* ((/ quotient) (q (/ n m)))
    (printf "~a ... ~a\n~a\n~a)~a\n"
        (div-num q 1)
        (remainder n m)
        (div-line)
        m 
        n)

    (let loop ((s0 (expt 10 (- (width n) 1))))
      (let ((s1 (if (= s0 1) 1 (/ s0 10))))
    (printf "~a\n~a\n~a\n" 
        (div-num (* m s0 (num-at q s0)) s0)    
        (div-line)
        (div-num (- n (* m (/ q s0) s0)) s1))
    (if (> s0 1)
        (loop s1))))))

Squeak Smalltalk で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| printWarizan |
printWarizan := [:n :m |
    | width line quo rem isFirst |

    n := n printString.
    m := m printString.
    width := n size + m size + 1.
    line := String new: n size + 1 withAll: $-.
    quo := n // m.
     
    Transcript cr.
    {quo. line. m, ')', n} do: [:each |
        Transcript cr; show: (each forceTo: width paddingStartWith: $ )].

    rem := ''.
    isFirst := true.
    n size to: 1 by: -1 do: [:idx |
        | digit |
        rem := rem copyWith: (n atLast: idx).
        digit := (quo atLast: idx ifAbsent: [$0]) asString.
        digit ~= '0' ifTrue: [
            | elems |
            elems := {rem. width - idx + 1. digit * m. width - idx + 1. line. width}.
            isFirst ifTrue: [isFirst := false. elems := elems allButFirst: 2].
            elems pairsDo: [:each :len |
                Transcript cr; show: (each forceTo: len paddingStartWith: $ )]].
        rem := rem - (digit * m)].

        Transcript cr; show: (n \\ m forceTo: width paddingStartWith: $ )].

World findATranscript: nil.
printWarizan value: 123456 value: 77

"=>
     1603
  -------
77)123456
    77
  -------
    464
    462
  -------
      256
      231
  -------
       25
"

Pythonでゴリゴリと。 文字列と整数の変換を繰り返したり、式が長かったり、無駄に条件分けがあったり、いろいろと汚いですが……

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/python                     
# coding: utf-8                       

# aわるbを実装します
a = 123456          
b = 77              

# 割り算の筆算を表示する関数
def warizan(a, b):          
        # 数字の桁数を求める関数
        digit = lambda x: len(str(x))

        ans_div = a // b
        ans_mod = a % b 

        print (digit(a) + digit(b) + 1 - digit(ans_div)) * ' ' + \
                str(ans_div) + ' ... ' + str(ans_mod)
        print digit(b) * ' ' + (digit(a) + 1) * '-'
        print str(b) + ')' + str(a)

        start = (digit(a) + digit(b) + 1 - digit(ans_div))
        # 引く数
        minuses = [int(str(ans_div)[i]) * b for i in range(digit(ans_div))]
        # 引かれる数
        minuend = int(str(a)[0:digit(a)-digit(ans_div)+1])
        # 引いた後に下に下ろしてくる数字(aを一桁ずつ)
        downs = [int(str(a)[i]) for i in range(digit(a) - digit(ans_div)+1, digit(a))]
        downs.append(None)
        for minus, down in zip(minuses, downs):
                if minus != 0:
                        print (start + 1 - digit(minus)) * ' ' + str(minus)
                        print (start + 1 - max(digit(minuend), digit(minus))) * ' ' + \ 
                                 (max(digit(minuend), digit(minus)) + 1) * '-'
                start += 1
                minuend = (minuend - minus)*10 + down if down != None else minuend - minus
                if minuend >= b or down == None:
                        print (start + 1 - digit(minuend)) * ' ' + str(minuend)


# 関数呼び出し
if __name__ == '__main__':
        warizan(a, b)

$ wari 12345 67
     184
  ------
67)12345
    67
  ------
    564
    536
  ------
     285
     268
  ------
      17
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function wari() {
    local -i m=$1
    local -i n=$2
    local r=$(printf '%*d' ${#m} $((m / n)))
    write_head $m $n "$r"
    write_body $m $n "$r"
}

function write_head() {
    local m=$1
    local n=$2
    local r=$3

    repeat_char ' ' $((${#n} + 1))
    echo "$r"
    write_bar $m $n
    echo "$n)$m"
}

function write_body() {
    local m=$1
    local n=$2
    local r=$3
    local rest flag i

    for ((i = 0; i < ${#r}; i++)) {
        local c=${r:i:1}
        rest="$rest${m:i:1}"
        if [[ "$c" == [1-9] ]]; then
            [ -n "$flag" ] && printf '%*d\n' $((i + ${#n} + 2)) $rest
            printf '%*d\n' $((i + ${#n} + 2)) $((c * n))
            write_bar $m $n
            rest=$((rest - (c * n)))
            flag=1
        fi
    }
    [ -z "$flag" ] && write_bar $m $n
    printf '%*d\n' $((i + ${#n} + 1)) $rest
}

function write_bar() {
    local m=$1
    local n=$2
    repeat_char ' ' ${#n}
    repeat_char - $((${#m} + 1))
    echo
}

function repeat_char() {
    local c=$1
    local n=$2
    while ((n--)); do
        echo -n "$c"
    done
}

JavaScriptで。手抜きHTMLに入れてありますが、このままでも大抵のブラウザで動くと思います。

どうせすっきり書けないだろうしというわけで、整数範囲で割れるだけ割るのに加えて、商の各桁について「0」以外が得られてからf桁に達したら筆算を止める(f桁に達しないうちは小数点以下になっても続ける)、というのも入れてみました。で、予想以上にごちゃごちゃ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<body>
<script>
function divOnPaper(n, m, maxFigs) {
    n = Math.floor(Number(n)); n = (isNaN(n)||n < 1) ? 1 : n;
    m = Math.floor(Number(m)); m = (isNaN(m)||m < 1) ? 1 : m;
    maxFigs = Math.floor(Number(maxFigs)); maxFigs = (isNaN(maxFigs)||maxFigs < 0) ? 0 : maxFigs;

    var q = [0], strQ = "", strN = n.toString(), qm, r = 0, exp = strN.length - 1;
    var limitToInt = !maxFigs, firstFig = false;
    var note = maxFigs ? "(up to " + maxFigs + " figures)" : "(within integer)",
        rowQ, rowMN = insSP(m) + " ) " + insSP(n), rowsQMR = "", rowR0, rowR1;

    while ((r || strN) && (limitToInt ? exp >= 0 : maxFigs)) {
        r *= 10;
        if (strN) {
            r += Number(strN.substring(0, 1));
            strN = strN.substring(1);
        }

        if (r >= m) {
            rowR1 =       repeatStr(" ", (rowMN.length - 2 * exp - insSP(r ).length)) + insSP(r );
            if (firstFig) {rowsQMR += rowR1.substring(rowR0.length) + "\n";} 

            qm = r - r % m;
            q[exp] = qm / m;
            r = r % m;

            rowsQMR += repeatStr(" ", (rowMN.length - 2 * exp - insSP(qm).length)) + insSP(qm) + "\n";
            rowsQMR += repeatStr(" ", (rowMN.length - 2 * exp - insSP(qm).length) - 1);
            rowsQMR += repeatStr("-", (insSP(qm).length) + 2) + "\n";
            rowR0 =       repeatStr(" ", (rowMN.length - 2 * exp - insSP(r ).length)) + insSP(r );
            rowsQMR += rowR0;

            firstFig = true;
        } else {
            if (firstFig || exp < 0) q[exp] = 0;
        }

        exp--; 
        if (firstFig) maxFigs--;
    }

    var i = exp; while (i > 0) q[i--] = 0;

    i = q.length - 1; while (i >= 0) strQ += q[i--].toString();
    if (typeof q[i] == 'number') strQ += ".";
    while (typeof q[i] == 'number') strQ += q[i--].toString();

    var summary = "n = m * q + r " + note + "\n" +
        "n: " + n + "\n" +
        "m: " + m + "\n" +
        "q: " + strQ + "\n" +
        "r: " + Number(r + "." + strN + "e" + (exp + 1));
    rowQ = repeatStr(" ", (rowMN.length - insSP(strQ).match(/(?:\d| )+/)[0].length)) + insSP(strQ);
    rowQ += "\n" + repeatStr(" ", insSP(m).length + 1) + repeatStr("-", (rowQ.length - insSP(m).length));

    return summary + "\n\n" +rowQ + "\n" + rowMN + "\n" + rowsQMR + "\n\n\n";

    function insSP(str) {
        return str.toString().replace(/(\d)(?=\d)/g, "$1 ");
    }
    function repeatStr(str, num) {
        return (new Array(num+1)).join(str);
    }
}
</script>

<form>
n: <input id="n" type="text">&nbsp;&nbsp;&nbsp;&nbsp;
m: <input id="m" type="text">&nbsp;&nbsp;&nbsp;&nbsp;
f: <input id="f" type="text">&nbsp;&nbsp;&nbsp;&nbsp;
<input id="calc" type="button" value="calc"><br>
<textarea id="rslt" style="font-size: 0.8em; line-height: 0.9em; width: 100%; height: 30em;"></textarea>
</form>

<script>
function calc(){
    n = document.getElementById("n").value;
    m = document.getElementById("m").value;
    f = document.getElementById("f").value;
    document.getElementById("rslt").value = divOnPaper(n, m, f);
}
document.getElementById("calc").onclick = calc;
document.write("<h4>examples:</h4><pre style=\"font-size: 0.8em; line-height: 0.9em;\">" +
    divOnPaper(1000, 71) + "\n" +
    divOnPaper(1000, 71, 4) + "\n" +
    divOnPaper(123456789, 57, 0) + "\n" +
    divOnPaper(123456789, 57, 2) + "\n" +
    divOnPaper(1000, 7, 0) + "\n" +
    divOnPaper(1000, 7, 2) + "\n" +
    divOnPaper(1000, 7, 3) + "\n" +
    divOnPaper(1000, 7, 4) + "\n" +
    "</pre>");
</script>
</body>

Javaで。割とコンパクトに書けたかな?
------
実行結果

    10775
   ------
13)140077
   13
   ------
    100
     91
    -----
      97
      91
      ---
       67
       65
       --
        2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package doukaku;

import java.io.*;

public class Warizan {

   public static void main(String[] args) {
      print(new PrintWriter(new OutputStreamWriter(System.out)),140077, 13);
   }

   private static int xxx(int a) {
      return (a < 10) ? 1 : 10 * xxx(a / 10);
   }

   public static void print(PrintWriter w, int a0, int b) {
      int a = a0;
      int indent = ("" + b).length() + 1;

      String sp = (b + ")" + a).replaceAll(".", " ");
      String bar = sp.replace(' ', '-');

      w.printf("%s%" + ("" + a).length() + "d%n", sp.substring(0, indent), a / b);

      w.printf("%s%s%n", sp.substring(0, indent), bar.substring(indent));
      for (int c = xxx(a); c != 0; c /= 10) {
         final int d = a / c;
         final int e = (d / b) * b;

         if (e == 0) continue;

         final String ds = "" + d;

         if (a == a0) w.printf("%d)%d%n", b, a);
         else w.printf("%s%s%n", sp.substring(0, indent), ds);

         w.printf("%s%" + ds.length() + "d%n", sp.substring(0, indent), e);
         w.printf("%s%s%n", sp.substring(0, indent), bar.substring(indent));

         indent += ds.length() - Integer.toString(d - e).length();
         if(d == e) indent++;
         a -= e * c;
      }
      w.printf("%" +sp.length() +"d%n",  a);
      w.flush();
   }
}

15桁までしか対応しません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/perl
use strict;
use warnings;

div(@ARGV);

sub div{
    return if scalar @_ != 2;
    for(@_){ return unless /^[1-9]\d*$/; }
    my ($x, $y) = @_;
    
    my $line_length = length($x) + length($y) + 1;
    my $ans = int($x / $y);
    my $mod = $x % $y;
    my $field_length = my $offset = length($y);
    $field_length++;
    
    printf "%${line_length}d\n", $ans;
    print  ' ' x $offset . '-' x ($line_length - $offset) ."\n";
    print  "$y)$x\n";
    
    return if $ans == 0;
    
    my @ans_nums = split //,$ans;
    my @x = split //,$x;
    my $dest_minus = '';
    my $not_first_line = 0;
    while(defined(my $ans_num = shift @ans_nums) && $offset++){
        next if $ans_num == 0;
        
        my $src_minus = $ans_num * $y;
        $dest_minus .= shift @x while ($dest_minus || 0) < $src_minus;
        
        printf ' ' x $offset . "%${field_length}d\n", $dest_minus if $not_first_line++;
        printf ' ' x $offset . "%${field_length}d\n", $src_minus;
        print  ' ' x $offset . '-' x ($line_length - $offset) ."\n";
        
        $dest_minus -= $src_minus;
            $dest_minus = '' if $dest_minus == 0;
    }
    printf "%${line_length}d\n", $mod;
}

(warizan 9876 11)の結果 # ずれて見えるけど端末上では一応揃っている...

      897 ... 9
   -----
11 |9876
    88
   -----
    107
     99
   -----
      86
      77
   -----
       9
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(defun warizan (n m)
  (let* ((ret (floor (/ n m)))
     (tochu n)     
     (calc-keta (lambda (x) (if (plusp x) (floor (log x 10)) 0)))
     (string-concatenate (lambda (x &optional (s " ")) (apply 'concatenate 'string (make-list x :initial-element s))))
     (keta (funcall calc-keta n))
     (space-num (+ 3 (funcall calc-keta m)))
     (keisen (format nil "~a~a~%" (funcall string-concatenate (1- space-num)) (funcall string-concatenate (+ 2 (funcall calc-keta n)) "-")))
     )
    (format t "~a~d ... ~d~%" (funcall string-concatenate (- (+ space-num keta) (funcall calc-keta ret))) ret (- n (* m ret)))
    (format t keisen)
    (format t "~d |~d~%" m n)
    (dotimes (i (1+ keta))
      (let* ((kurai (- keta i))
         (p (* (floor (/ ret (expt 10 kurai))) (expt 10 kurai)))
         (c (* p m))
         )
    (decf tochu c)
    (decf ret p)
    (when (> c 0)
      (format t "~a~d~%" (funcall string-concatenate (- (+ space-num keta) (funcall calc-keta c))) (floor (/ c (expt 10 kurai))))
      (format t keisen)
      (format t "~a~d~%" (funcall string-concatenate (- (+ space-num keta) (funcall calc-keta tochu))) (floor (/ tochu (expt 10 (if (plusp kurai) (- kurai 1) kurai)))))
      )
    )
      )
    )
  )

ふと無名関数が使いたくなったので、Visual Studio 2010 CTP付属のコンパイラを使いました。しかし、出来上がったものを見てみれば、ラムダ要らないのでは?という仕上がりですが、このまま投稿してしまいます。

除数・被除数を入力してください。
8956
12

   0746
   ----
12)8956
   0
   ----
   89
   84
   ----
    55
    48
   ----
     76
     72
   ----
      4
答え合わせ: 8956 / 12の商・剰余は746 … 4
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <sstream>
#include <iomanip> // setw
#include <string>
#include <cmath> // log10
#include <cstdlib> // div

int digit(int n)
{
    return static_cast<int>(std::log10(static_cast<double>(n))) + 1;
}

std::ostream& print_c_n(std::ostream& os, char c, unsigned n)
{
    for (unsigned i = 0; i < static_cast<unsigned>(n); ++i)
    {
        os << c;
    }
    return os;
}

void print_divition(int x, int y)
{
    using namespace std;
    ostringstream os;
    os << y << ')';
    unsigned left = static_cast<unsigned>(os.tellp());
    os << x << '\n';
    print_c_n(cout, ' ', left);
    int digit_x = digit(x); // 十進法での桁数

    // []の中は、外側の変数を「=」値渡し、ただしosのみ「&」参照渡しで受け取るの意
    auto nextDigit = [=, &os](int r, int i) -> int 
    {
        int u = x / static_cast<int>(pow(10., digit_x - i - 1)) % 10;
        int t = r * 10 + u;
        if (i != 0)
            os << u << '\n';
        div_t d = div(t, y);
        std::cout << d.quot;
        print_c_n(os, ' ', left) << std::setw(i + 1) << d.quot * y << '\n';
        print_c_n(os, ' ', left);
        print_c_n(os, '-', digit_x) << '\n';
        print_c_n(os, ' ', left) << std::setw(i + 1) << d.rem;
        return d.rem;
    };
    int r = 0;
    for (int i = 0; i < digit_x; i++)
    {
        r = nextDigit(r, i);
    }
    cout << '\n';
    print_c_n(cout, ' ', left);
    print_c_n(cout, '-', digit_x);
    cout << '\n' << os.str() << '\n';
    div_t d = div(x, y);
    cout << "答え合わせ: " << x << " / " << y << "の商・剰余は" << d.quot << " … " << d.rem << endl;
}

int main()
{
    int m, n;
    std::cout << "除数・被除数を入力してください。" << std::endl;
    std::cin >> m >> n;
    std::cout << '\n';
    print_divition(m, n);
}

n と m を直接計算せずに求めています。

> divide 123456 77;;
     1603
  -------
77)123456
    77
   ----
    464
    462
    -----
      256
      231
      ---
       25

val it : unit = ()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#light

let divide n m =
    let digits =
        Seq.unfold (fun x -> if x > 0 then Some (x % 10, x / 10) else None)
        >> Seq.to_list >> List.rev

    let rec calc result index remainder = function
        | [] -> (index - 1, remainder, None)::result |> List.rev
        | n'::ns ->
            let dividend = remainder * 10 + n'
            calc ((index, dividend, Some (dividend / m))::result) (index + 1) (dividend % m) ns

    let print result =
        let length x = (string x).Length
        let quotient = 
            result |> List.fold_left (fun sum (_, _, quot) ->
                match quot with Some q -> sum * 10 + q | None -> sum) 0
        let result' =
            result |> List.filter (function _, _, Some q when q = 0 -> false | _, _, _ -> true)
        let indent = length m + 1
        let numbers =
            result' |> List.mapi (fun i (index, dividend, quot) ->
                let indent' = indent + index
                (if i = 0 then "" else sprintf "%*d\n" indent' dividend) ^
                    (match quot with None -> "" | Some q -> sprintf "%*d\n" indent' (m * q)))
        let lines =
            result' |> Seq.pairwise |> Seq.to_list
            |> List.map (fun ((index, dividend, _), (index', _, _)) ->
                new string('-', index' - index + length dividend) |> sprintf "%*s\n" (indent + index'))
        let width = indent + length n
        printfn "%*d" width quotient
        new string('-', length n + 1) |> printfn "%*s" width
        printfn "%d)%d" m n
        List.map2 (^) (""::lines) numbers |> String.concat "" |> printfn "%s"

    digits n |> calc [] 1 0 |> print

*Main> :main 222222 111
      2002
   -------
111)222222
    222
    ------
       222
       222
       ---
         0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import Data.List                ( mapAccumL, unfoldr )
import System.Environment       ( getArgs )

longDivision :: Int -> Int -> String
longDivision n m = unlines $ showProcess n m $ getComponents n m

getComponents :: Int -> Int -> (Int, [Int], [Int], Int)
getComponents n m = (pack qs, ps, rs', last rs)
  where
    ns = unpack n
    (qs, ps, rs) = unzip3 $ snd $ mapAccumL dm 0 ns
    dm acc x = let { (q, r) = (10*acc + x) `divMod` m } in (r, (q, q*m, r))
    rs' = [head ns] ++ zipWith ((+) . (10*)) (init rs) (tail ns)

showProcess :: Int -> Int -> (Int, [Int], [Int], Int) -> [String]
showProcess n m (q, ps, rs, r) = quot_divs ++ div_steps ++ remainder
  where
    [w_n, w_m] = map (length . show) [n, m]
    w_mn = w_m + 1 + w_n

    quot_divs = [ showR q, divLineR (w_n+1), show m ++ ")" ++ show n ]
    div_steps = tail $ concat $ zipWith3 mkStep rs ps [w_m+2..]
    remainder = [ showR r ]

    mkStep _ 0 _ = []
    mkStep r p k = [ showAt k r, showAt k p, divLineR (w_mn - k + length (show r)) ]
    
    showR x    = rjustify w_mn $ show x
    divLineR w = rjustify w_mn $ replicate w '-'

-- misc
rjustify w xs = replicate (w - length xs) ' ' ++ xs
showAt   w x  = rjustify w $ show x

pack   = foldl ((+) . (10*)) 0
unpack = reverse . unfoldr phi
  where
    phi 0 = Nothing
    phi n = Just $ swap $ n `divMod` 10

swap (x,y) = (y,x)

main = do
  args <- getArgs
  let n:m:_ = map read args
  putStr $ longDivision n m

出力例 (535325 / 423)

 423)535325
1000 423000
-----------
     112325
 200  84600
-----------
      27725
  60  25380
-----------
       2345
   5   2115
-----------
        230
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static void Devide(int n, int m)
{
  int q = n / m;
  int lw = (int)Math.Log10(q > m ? q : m) + 1;
  string lf = "{0," + lw.ToString() + "}";
  int rw = (int)Math.Log10(n) + 1;
  string rf = "{0," + rw.ToString() + "}";
  string hl = new string('-', lw + 1 + rw);
  Console.Write(lf, m);
  Console.Write(')');
  Console.WriteLine(rf, n);

  for (int i = 0; i < lw; i++)
  {
    int d = lw - 1 - i;
    int u = (int)Math.Pow(10, d);
    int c = n / (u * m);
    if (c == 0) continue;
    int a = c * u;
    int b = a * m;
    Console.Write(lf, a);
    Console.Write(' ');
    Console.WriteLine(rf, b);
    Console.WriteLine(hl);
    n -= b;
    Console.Write(lf, ' ');
    Console.Write(' ');
    Console.WriteLine(rf, n);
  }
}

かなり愚直に実装してみました。

 $ ruby divide.rb 312456 521
        599
    -------
 521)312456
     2605
     -----
      5195
      4689
      -----
       5066
       4689
       ----
        377
 
       2002
    -------
 111)222222
      222
      ----
         2
         0
         --
         22
          0
         ---
         222
         222
         ---
          0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def divide(m, n) # m / n
  digit = keta(m) - keta(n)
  until (rem = m / (10**digit)) > n
    digit -= 1
  end
  dend = rem
  m1 = m % (10**digit)
  history = []
  digit.downto(0){|i|
    base  = 10 ** (i-1)
    quot  = dend / n
    rem   = dend % n
    history << [dend, quot, quot*n]
    dend = rem * 10 + m1 / base
    m1 %= base
  }
  (d,_,h) = history[-1]
  return history << [d - h, 0, 0]
end

def keta(n)
  return 1 if n == 0
  return Math.log10(n.to_i).floor + 1
end

if $0 == __FILE__
  m, n ,= ARGV.map(&:to_i)
  mketa = keta(m)
  nketa = keta(n)
  rslt = divide(m,n)
  tochu, last = rslt[0..-2], rslt[-1]
  width = mketa+nketa+1
  printf "%#{width}s\n", tochu.map{|a|a[1]}.join("")
  puts (" "*nketa)+("-"*(mketa+1))
  printf "%d)%d\n", n, m
  st = tochu.size - 1
  tochu.each_with_index{|(dend, quot, hiku), ind|
    k = nketa*2+2+ind
    if ind > 0
      printf "%#{k}d\n", dend
    end
    printf "%#{k}d\n", hiku
    hosei = st == ind ? 0 : 1
    hw = keta(dend) + hosei
    printf "%#{k+hosei}s\n", "-" * hw
  }
  printf "%#{width}d\n", last[0]
end

sawatさんによるJava版の移植です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int xxx(int a) {
  (a < 10) ? 1 : 10 * xxx((int)a / 10);
}

Integer.metaClass.width = {(delegate as String).size()}
Integer.metaClass.padLeft = {n->(delegate as String).padLeft(n)}

def printexp(indent, exp, width)  {
  println(' '*indent + exp.padLeft(width))
  println(' '*indent + '-'*width)
}

def waru(int a0, int b) {
  int a = a0
  int indent = b.width() + 1

  printexp(indent, (int)a/b, a.width())

  for (int c = xxx(a); c != 0; c /= 10) {
    int d = a / c
    int e = (d / b) * b
    if (e == 0) continue
    
    if (a == a0) println(b+")"+a)
    else println('>' * indent+d)

    printexp(indent, e, d.width())

    indent += d.width() - (d - e).width()
    if (d == e) indent++
    a -= e * c
  }
  println(a.padLeft(b.width()+a0.width()+1))
}

waru(140077, 13)

Scalaらしく(?)作ってみました。#過去の課題でこっそり勉強中です。。

-- 実行結果
123456
77
     1603
   ------
77)123456
    77
   ------
    464
    462
   ------
      256
      231
   ------
       25
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
object DivCalc {
    def main(args : Array[String]) : Unit = {
        val n = Console.in.readLine.toLong
        val m = Console.in.readLine.toLong
        Div(n, m).print
      }
}

case class Div(n:Long, m:Long) {
    def print = {
        println( idt + fmt(ans) )
        println( idt + line )
        println( m + ")" + fmt(n) )
        calc.take(1).foreach( x => println( idt + fmt(x._2, x._3) ) )
        calc.drop(1).foreach( x => {
            println( idt + line )
            println( idt + fmt(x._1, x._3) )
            println( idt + fmt(x._2, x._3) )
        })
        if (calc.isEmpty) println( idt + fmt(0) )
        println( idt + line )
        println( idt + fmt(mod) )
    }

    def len(a:Any) = a.toString.length
    def fmt(x:Any):String = fmt(x, 0)
    def fmt(x:Any, i:Int):String = idt(" ", len(n) - len(x) - i) + x
    def line = idt("-", len(n))
    def idt:String = idt(" ", len(m) + 1)
    def idt(c:String, i:Int):String = c * i

    val ans:Long = n / m
    lazy val mod:Long = n % m
    lazy val calc:List[(Long, Long, Int)] = {
        def process(n:Long, m:Long, c:Int):List[(Long, Long, Int)] = {
            val pow = Math.pow(10, c).toLong
            val x = if (pow == 0) { 0L } else { n / pow / m * m }
            (n,m,c,x) match {
                case (_,_,c,_) if (c < 0) => Nil
                case (n,m,c,0) => process(n, m, c-1)
                case (n,m,c,x) => (n / pow, x, c) :: process(n - x * pow, m, c-1)
            }
        }
        process(n, m, len(n))
    }
}

F#で愚直な実装です。
> DivByHand 222222 111;;
      2002
    ------
111)222222
    222
    ------
       222
       222
    ------
         0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//bDigDisp 3 "k" 2 で"   kk"を表示
let bDigDisp padCount str strCount  =
   let rec sub subStr count limit res =
        if count = limit then res
        else  sub subStr (count + 1) limit (res + subStr)
   printfn "%s" ((sub " " 0 padCount "") + (sub str 0 strCount ""))  

//numToList 1234 で[1;2;3;4]が返る
let numToList n  =
    let rec NtlSub m res =
        if m = 0 then 
            res
        else
            NtlSub (m/10) ((m - (m/10)*10)::res)
    NtlSub n []

let DivByHand num div =
    let numList = numToList num
    let divPadLen = (div.ToString()).Length + 1 
    let numLen = (num.ToString()).Length
    bDigDisp (divPadLen + numLen - ((num/div).ToString()).Length) ((num/div).ToString()) 1 
    bDigDisp divPadLen "-" numLen 
    printfn "%d)%d"div num        
    let rec dbhSub (carryIn:int) (remDigLst:int list)   (padLen :int)   (isFirst : bool)=
        match remDigLst with
        | [] -> bDigDisp  (padLen - (carryIn.ToString()).Length)   (carryIn.ToString()) 1
        | hd::tl -> let targetNum = 10*carryIn + hd
                    if targetNum < div then
                        dbhSub targetNum tl (padLen + 1) isFirst
                    else
                        let quoTemp = targetNum/div
                        let subNumStr = (div*quoTemp).ToString()
                        if(isFirst <> true) then 
                            bDigDisp (padLen - (targetNum.ToString()).Length + 1 ) (targetNum.ToString()) 1 
                        bDigDisp (padLen - subNumStr.Length + 1 ) subNumStr 1 
                        bDigDisp divPadLen "-" numLen 
                        dbhSub (targetNum % div) tl (padLen + 1)  false
    dbhSub 0 numList divPadLen true

Index

Feed

Other

Link

Pathtraq

loading...