プログラミング入門II
2024.05.29
関数 その1

Back to index page



  1. 本日の作業内容

  2. 前回の宿題について

    残念ながら今回はエラーになるものが出てきてしまいました.エラーメッセージをよく読んでほしいですが,それ以前にやっていることが全く理解できていない状況のように推測されますので,演習の際に質問するなどして,各回の演習問題を理解するようにしていきましょう.

    エラー: b2311

    他には解答用紙の学生番号と名前のところを自分のものに変更していない人が相変わらず出ています.こちらも注意しましょう.

    学生番号と名前間違い: b2301 b2306
    出力時番号間違い: b2301 b2306

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

    num1 = (random.randint(1000,9999)*10)
    num2 = (random.randint(1000,9999)*10)
    
    ......
    
    print(set(num1) & set(num2))
    

    上のものがエラーになったものです.単純な整数 num1 や num2 を集合にしようとしているので,えらーになりますね.

    Common = set(lst1) & set(lst2)
    

    変数名などは小文字で始めましょう.

    print(f'Divsors of {num1}:', *lst1)
    print(f'Divsors of {num2}:', *lst2)
    

    綴りの間違いもときどき見られます.約数の英語は divisor です.見本からコピペするだけでもいいのですが.

    print(f'Diviors of {num1}: ', end='')
    

    こちらも同じように綴りの間違いです.

    z = 1000
    n = [10 * i for i in range(z,10*z)]
    num1 = n[random.randint(0, 9*z-1)]
    
    print(f'Divisors of {num1}: ' ,end = '')
    

    ただ単に5桁の10の倍数を出すのに,9000個も乱数を発生させる必要がありますかねえ.発想がよくわからないです.

    num1 = random.randint(10000, 99999)
    num2 = random.randint(10000, 99999)
    

    上のものは結構見られた間違いです.公約数が少ないと表示が寂しいので,必ず4個以上の公約数が出るように10の倍数にしたのですが,そこを無視する人が何人もいました.

    a1 = 10 * random.randint(1,9999)
    b1 = 10 * random.randint(1,9999)
    

    これも間違っていますね.2桁から5桁の10の倍数が用意されますね.

    num1 = random.randint(100, 999)
    num2 = random.randint(100, 999)
    
    num3 = num1 * 100
    num4 = num2 * 100
    

    上のように100の倍数になっている人もいました.

    num1 = random.randint(10000, 99999) * 10
    num2 = random.randint(10000, 99999) * 10
    

    今度は6桁の整数にしている人も見られました.注意しましょうね.

    while count < 2:
        num = random.randint(10000, 99999)
        if num % 10 == 0:
            numbers.append(num)
            count += 1
    

    こちらも2個の乱数をだすだけで,こんな処理を書きますかねえ.もっと簡単にいきましょう.

    n1 = random.randint(0,9999)
    n2 = random.randint(0,9999)
    num1 = 10 * n1
    num2 = 10 * n2
    

    処理自体は間違ってはいませんが,変数の無駄遣いですね.

    div = sorted(set(lst1) & set(lst2))
    
    print(f'Common divisors: {div}')
    

    アンパックしないで表示させている人も何人かいました.下のようにカッコつきで出てきてしまいます.

    Common divisors: [1, 2, 4, 5, 10, 20]
    

    div1 = [i for i in range(1, num1 + 1) if num1 % i == 0]
    div2 = [i for i in range(1, num2 + 1) if num2 % i == 0]
    
    
    com=[i for i in range(1, min(num1, num2) + 1) if num1 % i== 0 and num2 % i==0]
    

    内包表記で約数を探すスマートな方法ですが,div1 と div2 でせっかく約数を見つけているのに,公約数を改めて求める処理を書いています.それはやはり問題があるので,減点とさせてもらいました.反復処理は計算機に時間コストをかけるので,そこは集合でさっと求めたいですね.

    for k in range(1,99999):
        if (num[0] % k == 0) and (num[1] % k == 0):
            print(f'{k}', end = ' ')        
    

    こちらも公約数を改めて求めてしまっている例です.

    if num3 < num4:
        les = num3
    else:
        les = num4
    for i in range(1, les + 1):
        if num3 % i == 0 and num4 % i == 0:
            gcd_l = i
    
    for i in range(1, gcd_l + 1):
        if gcd_l % i == 0:
            print(f'{i} ', end = '')
    else:
        print()
    

    上のものもやはり公約数を改めて反復処理で求めている例です.結構ややこしいことになっていますね.集合は Python ならではの便利な機能なので,使いましょう.

    print(*set(div1) & set(div2))
    

    問題のところに公約数は小さい順に表示されるようにすることを指示していましたが,何も処置をしないと下のように表示されます.そこに気づきませんでしたでしょうか.何人かの人がこうなっていました.

    Common divisors: 1 2 10 5
    

    print(f'Divisors of {num1}: ',end='')
    print(*lst1)
    print(f'Divisors of {num2}: ',end='')
    print(*lst2)
    
    print(*set(lst1) | set(lst2))
    

    よくわからない print があります.和集合を求めています.そのため,下のように無駄な数がたくさん表示されます.

    Divisors of 91640: 1 2 4 5 8 10 20 29 40 58 79 116 145 158 232 290 316 395 580 632 790 1160 1580 2291 3160 4582 9164 11455 18328 22910 45820 91640
    Divisors of 61820: 1 2 4 5 10 11 20 22 44 55 110 220 281 562 1124 1405 2810 3091 5620 6182 12364 15455 30910 61820
    1 2 4 5 8 1160 10 395 91640 11 145 3091 20 61820 790 22 18328 281 29 158 290 6182 40 1580 44 562 55 58 316 30910 11455 580 9164 12364 79 3160 220 15455 1124 4582 232 110 2291 116 5620 632 2810 45820 1405 22910

    本日から行う内容である関数を使用し,また今後活用をしていく予定の map 関数もつかっています.処理に問題は無いのですが,以前にも書いたように,こういうのを本当に自分で作りましたかねえ?ダウトです.

    num1 = random.randint(1000, 9999)*10
    num2 = random.randint(1000, 9999)*10
    
    def find_divisors(n):
        divisors = [i for i in range(1, n + 1) if n % i == 0]
        return divisors
    
    divisors1 = find_divisors(num1)
    divisors2 = find_divisors(num2)
    
    print(f"Divisors of {num1}: {' '.join(map(str, divisors1))}")
    print(f"Divisors of {num2}: {' '.join(map(str, divisors2))}")
    
    common_divisors = set(divisors1) & set(divisors2)
    
    print("Common divisors:", ' '.join(map(str, sorted(common_divisors))))
    

  3. 前回の復習

    リストとは異るタプルや辞書,集合について学習しました.実際にそれらが有用な場面にならないと意義を理解するのは難かしいかと思います.今回実習する関数では複数の戻り値を受け取る際にタプルが使われていますので,関数の学習を通してさらに勉強していきましょう.

  4. 関数

    これまでプログラムの中で print() や randint() などの関数を使ってきましたが,そのように何かの一連の作業をさせる関数を今回は自分で作ってみることになります.自分で作るので,「ユーザ定義関数」と言います.関数の定義,引数仕様,戻り値などいくつか重要な項目がありますので,それらについて学習しましょう.

    1. 引数

      関数には引数が必要なものと不要なものがありますが,引数を呼び出し時に与えるときに,実際に与える引数を「実引数」,関数が受け取る引数を「仮引数」と言います.実引数と仮引数は変数名が違っていても,呼び出しの際の記述位置で把握しますので問題ありません.

    2. 複数の戻り値

      複数個の戻り値の場合にはタプルを使うのが基本と教科書の p.247 にあります.実際にこの後の演習問題で試してみましょう.

    3. 再帰

      関数を学習する際に必ず例題として出てくるのが「再帰」です.漸化式で表現できる反復処理を実行する際に使用されます.ただし,動作は遅いので,反復処理の代わりに使用するものではなく,あくまでも漸化式表現の処理の実行に使用します.

      教科書の p.250 の List 9-9 にある階乗計算を for 文のものと比較してみましょう.この程度の数値では体感的な差は無いと思いますが.

      def factorial(n):
          if n > 0:
              return n * factorial(n - 1)
          else:
              return 1
      
      n = 900
      
      print(f'The factorial of {n} is {factorial(n)}.')
      
      n = 900
      fact = 1
      
      for i in range(1,901):
          fact *= i
      
      print(f'The factorial of {n} is {fact}.')
      
      再帰版 for 文版

  5. 演習

    今回の演習問題です.

  6. 宿題

    いつものようにレポート提出システムを利用します.授業当日の18:00から閲覧可能で,締切りは翌週月曜日の10:00です.

  7. 次回の予習範囲

    次回は教科書のp.268-294の範囲を学習しますので,予習をしてきてください.


目次ページに戻る