プログラミング入門I
2024.12.09
多重ループ

Back to index page



  1. 本日の作業内容

  2. 前回の宿題について

    今回もエラーになるものがなくうれしく思いました.また,基本的にはできているので,そちらも安心しました.ただ,形式的な不備はなかなかなくなりません.

    解答用紙の名前未修正: b2448

    解答用紙の番号間違い: b2412 b2448

    出力時番号間違い: b2412 b2448

    以下は例によって問題のあるプログラムの例です.参考にしてください.

    mPn = math.perm(m, n)
    mCn = math.comb(m, n)
    

    何人くらい上のようにもとから用意されている関数を使用するかと興味を持って見ていましたが,結局一人でした.別に問題はありませんし.

    P_mn = 1
    

    変数名は小文字で始めるように何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も...

    num1=random.randint(7,10)
    num2=random.randint(3,5)
    num3=1
    for i in range(1,num1+1):
        num3 *= i
    num4=1
    for j in range(1,num1-num2+1):
        num4 *= j
    num5=1
    for k in range(1,num2+1):
        num5 *= k
        num6 = num3 / num4
        num7 = num3 / (num4 * num5)
    else:
        print()
    

    意味のある分かりやすい変数名を付けるようにいつも言っておりますが,上のようなものは分かりやすいですか?それと, for 文で使用する変数ですが, for 文は開始するときに毎回変数を初期化するので,i, j, k と違う名前をつける必要はありません.多重の for 文の場合には使い分けが必要ですが.

    for _ in range(num1-num2+1,num1+1):
        total*=_
    print(f'{num1}P{num2}={total}')
    sum1=total
    for i in range(1,num2+1):
        sum1 /= i
    print(f'{num1}C{num2}={int(sum1)}')
    

    前回も指摘しましたが,for 文で下線文字 _ を使用するのは,繰り返しの回数だけ指定するような変数を置く意味が無い場合です.スイーツで使用するのであれば,変数名を付けておきましょう.また,sum は和という意味ですから階乗計算の際に使用するのは適切ではありませんし,実数型の割り算も適切ではありません.

    m = random.randint(7, 10)
    n = random.randint(3, 5)
    
    if m < n:
        m, n = n, m
    

    乱数の範囲を見れば,今回 m < n になる可能性はありません.余分な if 文です.この if を使用しなくてすむように最初から範囲を指定していました.

    if m >= n:
        num1 = 1
        for i in range(m, m - n, -1):
            num1 *= i
        
        num2 = 1
        for i in range(1, n + 1):
            num2 *= i
        
        num3 = num1 // num2
        
        print(f'{m}P{n} = {num1}')
        print(f'{m}C{n} = {num3}')
    else:
        print()
    

    こちらも同じく if 文は必要ありませんね.

    for i in range(1,num_n+1):
        kai_n*=i
    else:
        print()
    for i in range(1,num_m+1):
        kai_m*=i
    else:
        print()
    for i in range(1,num_mn+1):
        kai_mn*=i
    else:
        print()
    

    なんで else で print 文が必要なんでしょうか?

    num5 = fact / fact2
    print(f'{num1}P{num2} = {num5:.0f}')
    

    上の例も整数型の除算をしないで実数型で計算しているので,小数部を表示しないようにしていますが,無駄な作業です.ほとんどのプログラミング言語は2進数が苦手な小数を扱わなくていいように整数型の演算を用意しています.整数型ですむのなら整数型のままで計算してください.

    順列や組わせの計算で割り算を行うのですが,この割り算は必ず割り切れます.余分な心配は不要です.自分で思いつく組み合わせを実際に書き下してみればすぐにわかります.

    print(f'{m}P{n} = {fact_m / fact_mn:.0f}')
    print(f'{m}C{n} = {fact_m / (fact_mn * fact_n):.0f}')
    

    こちらも同様ですね.整数型の割り算 // を使ってください.

        for _ in range(digit - 1):
            num1 *= num4
            num4 -= 1
            if num3 != 0:
                num1 /= num3
                num3 -= 1
            elif num5 != 0:
                num2 *= num5
                num5 -= 1
        
        print(f'{digit}P{digit2} = {int(num1)}')
        print(f'{digit}C{digit2} = {int(num1 / num2)}')
    

    こちらも実数型で計算しているため,不必要な int 関数までしようしています.

    p=1
    mx=0
    for i in range(2, m+1):
        p*=i
        if p>mx:
            mx=p
    
    pi=1
    mix=0
    for i in range(2, n+1):
        pi*=i
        if pi>mix:
            mix=pi
    
    pii=1
    miix=0
    for i in range(2, m-n+1):
        pii*=i
        if pii>miix:
            miix=pii
    

    よくわからない if 文が入っています.

    num1=num2=num3=1
    
    for i in range(1,m+1):
        num1 *= i
    for x in range(1,n+1):
        num2 *= x
    for y in range(1,m-n+1):
        num3 *= y
       
        
    else :
        print()
    c = num1 // (num2 * num3)
    print(f'{m}P{n} = {num1}')
    print(f'{m}C{n} = {c}')
    

    組み合わせの方は正しく計算しているのですが,順列の方がただの階乗計算になっているので,間違っています.実行例にある計算を実際に正しく計算できているのか,よく確認してください.

    num1=random.randint(7,10)
    num2=random.randint(3,5)
    num3=num1
    num4=num1
    num5=num2
    num6=num2
    for _ in range(num2-1):
        num4-=1
        num3*=num4
    print(f'10P3 = {num3}')
    for _ in range(num2-1):
        num6-=1
        num5*=num6
    num3/=num5
    print(f'10C3 = {num3}')
    

    これだけ紛らわしい変数名を用意してわけのわからない代入を行えば,計算結果が間違っているのも不思議ではないですね.以下のように小数部が出るような計算になっています.

    10P3 = 15120
    10C3 = 126.0
    

    fact1 = 1
    for i in range(1, numm + 1):
        fact1 *= i
    
    fact2 = 1
    for i in range(1, numn + 1):
        fact2 *= i
    
    fact3 = 1
    for i in range(1, numm-numn + 1):
        fact3 *= i
    
        nump=fact1/fact3
        numc=fact1/fact2 * fact3
    
        print(f'{numm}P{numn}={nump}')
        print(f'{numm}C{numn}={numc}')
    

    本来は for 文の外にあるべき処理がインデントされてしまっているので,反復処理となってしまい,以下のように表示が繰り返されることになってしまいました.自分でおかしいことに気づくでしょうから,何とか対応してください.Pythonはインデントが極めて重要ですので,今後は気をつけてください.

    8P5=40320.0
    8C5=336.0
    8P5=20160.0
    8C5=672.0
    8P5=6720.0
    8C5=2016.0
    

    print(f'順列 mPn={mPn}')
    print(f'組み合わせ mCn={mCn}')
    

    これまで何度か指摘してきたように,実行例を勝手に変えて自分で適当に用意しないでください.例えば私の環境で上のように日本語が入ったものを実行すると,以下のように文字化けします.また,乱数の m と n の値が表示されていないので,計算が合っているかの判定もできません.

    □□□□@mPn=15120
    □g□ݍ □ 킹 □@mCn=126
    

    print(f'm = {m}, n = {n}')
    print(f'mPn = {mPn}')
    print(f'mCn = {mCn}')
    

    実行例のようにきちんと f 文字列を使用して数字を入れておいてください.

    m = 9, n = 3
    mPn = 504
    mCn = 84
    

    print(m, n)
    for i in range(1, m + 1):
        add1 *= i
    else:
        print()
    for j in range(1, do + 1):
        add2 *= j
    else:
        print()
    for k in range(1, n + 1):
        add3 *= k
    else:
        print()
    print(f'10P{m} = {add1 // add2}')
    print(f'10C{m} = {add1 // (add2 * add3)}')
    

    出力結果の方は順列も組み合わせも m が10で固定されてしまっています.また m の値が n が表示されるべき場所にあります.別に print するくらいなら m も P や C の左側に出力しましょう.

    8 5
    
    
    
    10P8 = 6720
    10C8 = 56
    

  3. 前回の復習

    授業の最初に for 文に関する確認テストを行います.実際の作業については授業の中で指示します.

  4. 多重ループ

    繰り返しの処理の中に繰り返しを入れることが可能です.それにより2次元的な表現などが可能となります.教科書では九九の表の例が出ていますが,そのような縦と横に文字を並べる作業では以下の点がポイントとなります.

    2重の for 文のポイント

    for i in range(hoge):
        for j in range(huga):
            print(foo, end = '')
    

    外側のループの変数 i は行に対応し縦に進む処理で,内側の変数 j は各行内の表示で右に進める作業に対応します.例題を通して学習していきましょう.

  5. 演習

    今回の演習問題です.

  6. 本日のまとめ

    2重のループを使用して2次元表示的な作業を行いました.二つの変数(通常は i と j)が変化するとどのような処理になるのか,じっくりと考えながら作業を進めるようにしてください.その際にはフローチャート的な処理の組み立てを考えるステップと,思ったように結果が出ないときの処理を一つ一つ丁寧にたどっていって問題を見つけるステップが重要です.

  7. 宿題

    宿題が公開されるのは明日火曜日10:00の予定で,締切りは来週の月曜日12月18日の10:00です.レポート提出システムを使用します.

  8. 次回の予習範囲

    次回も引き続き教科書のp.102-114の範囲を学習しますので,予習をしてきてください.多重のループについて特に扱います.


目次ページに戻る