2023-2I プログラミング1 第03回 講義資料

2023年04月27日(木)5・6時限

1 準備

2 前回の復習

前回講義で学んだことの要点をおさらいしておきます(少しだけ新規の内容が含まれています)。

2.1 演習① ~前回の復習~

前回の学習内容です。どれだけ身についているでしょうか?

2.1.1 演習①-1

Python

時間短縮のため、次のテキストをコピペして使用すること。

演習①-1
変数を埋め込んだ文字列の出力
文字列に変数を埋め込んで出力するためには「f文字列」を使用する。
改行をつけずにprint関数で文字列を出力するには、引数にend=’’を追加する。

2.1.2 演習①-2

%reset -f
word1 = 'eye'
word2 = 'tooth'
print()

2.1.3 演習①-3

%reset -f
word = '無駄!'
print()

3 変数のクリア

Google Colab. において、あるコードセル内で作成(設定)した変数は 他のコードセルにも引き継がれます。実際に確認してみましょう (試してみましょう)。

コードセルを新規作成して次のプログラムをコピペして実行します (コードセルを実行する場合は、積極的にショートカットキー Ctrl+Enter を使用してください)。

word = '無駄!'
print(word*10)

次に、別のコードセルを新規作成して、次のプログラム「pg2.py」の内容をコピペして実行することを考えます。pg2.py の01行目では、あえて変数名の タイポ をしています。

wrod = 'オラ'
print(word*8)

上記プログラムを実行すると、01行目で文字列をセットしている変数名 wrod と、02行目で参照している変数名 word が違うので NameError: name 'wrod' is not defined というエラーがでるだろうと期待しますが、実際の結果はそうはなりません

先に実行したセルで作成された変数 word が内部に残っているのでエラーは発生しないものの、意図した結果が得られない という状況になります。

今回は、変数名に間違いがあることに気づいているために問題ありません。しかし、間違いに気づいていないときに「エラーは発生しないものの、意図した結果が得られない」というのは非常に厄介な状況 (バグ) になります。実際、これが原因で何時間も悩んだり、学習を挫折したりする初心者も珍しくありません。

コードセルを抜けても変数が生き残っていることは非常に便利な機能なのですが、状況によっては望ましくありません。そのような状況で役立つのが、変数をオールクリアするための %reset -f になります。既に第01回の講義資料から登場しています (きょうまでに解説されるのを待つことなく、自分で検索等して解決した人は大変に素晴らしいです )。

実際に、確認してみましょう。上記の2個目のプログラムを次のように書き換え (%reset -fを追記し) 、実行してみてください。

%reset -f
wrod = 'オラ'
print(word*8)

今度はエラーが発生するようになりました (エラーが発生することで「不具合の原因がどこにあるか」のヒントが得られるようになりました)。

3.1 演習

%reset -f%reset に書き換えて実行し (-fオプションを抜いて実行し)、どのように動作が変わるかを確認せよ。

コマンドのオプション

一般にコマンドの「オプション」の -f は「force (強制する)」を意味します。例えば、Linuxにおけるファイル削除のコマンド rm は、通常「本当に削除してよいか」の旨の確認がされますが rm -f のようにオプションをつけると「確認なし」で削除が実行されます。

よって、次のような -f オプションをつけたコマンドを安易に実行しないように十分に注意してください。

sudo rm -rf / --no-preserve-root

OS (Linux) が吹っ飛びます。

3.2 補足: マジックコマンド

GoogleColab. のコードセルのなかで % から開始する文をマジックコマンドといいます。マジックコマンドは、Python の文・機能ではなく、GoogleColab.(Jupyter) の文・機能であり、(Colab.以外の)ローカルのPython開発環境では使用できません。

一度は「Google Colab マジックコマンド」で検索してみてください。開発を効率的に進めることができる様々なマジックコマンドが存在しています。

4 変数の確認

GoogleColab. では、参照可能な変数 (定義されている変数)%who というマジックコマンドで確認することができます。

実際に確認してみましょう。コードセルを新規作成して、次のプログラムを実行してください。

apple = 'りんご'
banana = 'バナナ'

次に、別のコードセルを新規作成して、次のマジックコマンドを実行してください。

%who

現時点で定義済みの変数が表示されます。また、%whos%who_ls のマジックコマンドについても動作を確認してみてください。

その後、%reset -f を実行後、再度、各マジックコマンド (%who%whos) を実行して結果を確認してみてください。

5 変数に「数値」を代入して取り扱う

5.1 導入

ここまでは「変数」に文字列 (文字列リテラル) を代入するプログラムを扱ってきました (リテラルとは?)。その際、注意すべきことは、次のように 文字列をダブルクォーテーション、または、シングルクォーテーションで囲んで扱う (表現する) ということでした。

%reset -f
apple = 'りんご'
banana = "バナナ"
toeic_score = '350' # 文字列としての350
print( "apple = " + apple )
print( f'3-banana => {banana * 3}' )
print( f'TOEICスコア倍増! 目指せ{toeic_score * 2}')

特に、上記を実行した際、07行目の文によって出力される文字列に注意してください (どのような結果になるか、予想の上、実行してみてください)。ここで変数 toeic_score に格納されている「350」は「数値」ではなく「文字列」であるため、期待するような振る舞いはしません。

これは、f文字列の内部の特有の振る舞いではなく、次のようにプログラムを書いた場合でも同じです (期待するような文字列出力を得ることはできません)。

%reset -f
toeic_score = '350' # 文字列としての350
toeic_double_score = toeic_score * 2
print( '目指せ' + toeic_double_score )

5.2 変数に数値を代入

ここからは、変数に数値 (\(\neq\)文字列) を代入することを考えていきます。

中級者向け: 厳密には代入ではなくバインド(束縛)

前回も解説したように「整数値を変数に代入する」という表現は厳密には正しくありません (束縛する(バインドする)という表現が正しいです)。ただし、ここでは初心者向けに厳密さをある程度犠牲にして分かりやすさを重視して表現していることをご理解ください。

詳しくは 小山高専・技術支援室 を参照してください。

変数に数値 (\(\neq\)文字列) を代入するときは、次のようにシングル/ダブルクォーテーションで囲まずにイコールの右辺に数値を与えます。

%reset -f
toeic_score = 350 # "350" や '350' にしない
print( f'TOEICスコア倍増! 目指せ{toeic_score * 2}')

また、pi=3.14 のように 小数部を含む実数 を変数に代入することもできます。

なお、次のように f文字列 に埋め込まず、print関数の引数に直接変数を与えて、その内容を出力すること (表示すること) もできます。

%reset -f
toeic_score = 350
toeic_double_score = toeic_score * 2
print( toeic_score )
print( toeic_score, toeic_double_score )

また、次のように、直接、計算式を与えることもできます。

%reset -f
print( 350 * 2 )

5.3 Pythonで利用できる数値リテラル

Pythonでは、toeic_score = 350pi=3.14 以外にも、次のような数値リテラル (数値の表記) を使って変数に値を代入することができます。

桁数の大きな値 (例えば、300,000,000 = 30億) は、次のように与えることができます。

%reset -f
x1 = 300000000 # ノーマルな方法(ミスしやすい)
print(f'x1 = {x1}')

x2 = 300_000_000  # アンダーバーを数値区切りに利用
print(f'x2 = {x2}')

x3 = 3e+8 # e 3x10^8
print(f'x3 = {x3}')

2進数( Binary: バイナリ ) は、次のように先頭に 0b を付けて与えることができます (先頭に付ける文字を「prefix (プレフィックス)」、「接頭辞/接頭辞」とも表現します) 。また、10進数の場合と同様に、任意の位置 (好きな位置) に _ を入れることができます。

%reset -f
x1 = 0b1010 # 1010 => 8 + 2 = 10
print(f'x1 = {x1}')

x2 = 0b_1010 # 1010 => 8 + 2 = 10
print(f'x2 = {x2}')

x3 = 0b_0011_1010 # 0011 1010 => 32+16+8+2=58
print(f'x3 = {x3}')

注意

第01講義、第02回講義でも注意しましたが、解説を受ける / 解説を読む だけではなく、必ず手を動かして自分自身で「試してみること」「検証してみること」、また「例外はないのか?などについて考えてみること」を忘れないでください。

例えば、プレフィックスであれば「0B のような大文字でもよいのか」「00Bのようなゼロ2連続でもよいのか」、 数値区切りのアンダーバーであれば「2個連続で使えるのか」「数値リテラルの先頭や末尾でも使えるのか」「プレフィックスの途中で 0_b_1100 のように使えるのか」のようなことが発想ができ、結果を予想し、それを試して、規則性などを見いだせるようになってください (このようなことができる人が最終的に高いスキルを習得できます)。

また、同時に、いま学んでいることが「日常の生活や教科学習では、どのように利用できそうか」「自分がつくりたいモノ (例えばゲーム) にどのように利用できそうか」という視点も常に持つようにしてください。

16進数( Hexadecimal: ヘクサデシマル ) は、次のように与えることができます。16進数の「A」から「F」は大文字でも、小文字でも、どちらでも表記できます。

%reset -f
x1 = 0xFF
print(f'x1 = {x1}')

x2 = 0xff
print(f'x2 = {x2}')

x3 = 0x_ffEE6a # 大文字と小文字の混合
print(f'x3 = {x3}')

5.4 四則演算

整数」または「小数を含む実数」が数値が格納された変数に対しては、次のように四則演算をすることができる。

%reset -f
a, b = 7, 2  # a=2 と b=6 を1行で記述

x = a + b   #「x1=a+b」のようにスペースを含めず記述も可
print(f'(1) {a}+{b}={x}')

x = a - b 
print(f'(2) {a}-{b}={x}')

x = a * b  # 乗算(掛け算)。「*」はアスタリスクと読む。
print(f'(3) {a}*{b}={x}')

x = a / b  # 除算(割り算)
print(f'(4) {a}/{b}={x}')

x = a % b  # 何を計算しているか検証せよ。
print(f'(5) {a}%{b}={x}')

x = a // b  # 何を計算しているか検証せよ。
print(f'(6) {a}//{b}={x}')

上記の (5) と (6) については、変数の値を変更しながら「何を計算しているのか」を検証してください。特に、変数に格納される値が「小数」や「負数」となったとき、どのような挙動をするのかも、検証してください。

5.4.1 演習②

変数 a に10、変数 b に5、変数 c に2を代入して次の値を計算せよ。さらに、正しく計算できているかどうかを、手計算やExcelを使用した計算、周囲の学生と突き合わせることで検証せよ。

\[ (1)\ \ \ 6ab^{2} \]

\[ (2)\ \ \ -3(a+b)\{(a+c)-(b+c^2)\} \]

\[ (3)\ \ \ -\frac{3b^2}{6a+2c} \]

注意

ChatGPT等の登場により「(正当性の保証はないものの) とりあえずの答えをだすこと」は、ほぼ誰でも「できてしまう時代」となりました。そのうえで、重要なことのひとつとして「解の検証」があります。

「情報1」や「情報2」の授業でも伝えているように「技術者には自分自身で解の妥当性を検証し、それに責任を負うことが求めれる」ということを意識して、そのための訓練や習慣づくりをするようにしてください。

5.5 出力の書式指定

変数に格納した数値を、文字列として出力する際、次のように 書式 (フォーマット) を指定することができます。f文字列のなかで、: に続けて書式指定子を記述します。

%reset -f
a = 45 # 整数値
print(f'a={a}')       # 書式指定なし
print(f'a={a:.2f}')   # 小数点以下桁数指定
print(f'a={a:b}')     # 2進数 1+4+8+32
print(f'a={a:_b}')    # 2進数 区切り文字あり
print(f'a={a:09_b}')  # 2進数 ゼロ埋め・出力桁数指定
print(f'a={a:x}')     # 16進数 13+32
print(f'a={a:X}')     # 16進数 大文字
print(f'a={a:04X}')   # 16進数 ゼロ埋め

小数を含む場合の例を示します。特に桁数が指定されたとき、四捨五入されるのか、切り捨てられるのか、切り上げられるのか、それともそれ以外なのか、予想し、検証してください。

%reset -f
a = 0.62184 # 実数
print(f'a={a}')      # 書式指定なし
print(f'a={a:.3f}')  # 小数点以下の桁数指定
print(f'a={a:.4f}')  # 小数点以下の桁数指定
print(f'a={a:e}')    # 指数表示
print(f'a={a:.3e}')  # 指数表示+桁数指定
print(f'a={a:.3E}')  # 指数表示
print(f'a={a:%}')    # パーセント
print(f'a={a:.1%}')  # パーセント+桁数指定

このほかにも多数の書式が存在します。必要に応じて「python f文字列 書式指定」などでウェブ検索して使えるようになっておいてください。

頻繁に使用する書式以外を暗記する必要はありませんが、その存在を意識して、必要に応じて利用できるようになっておいてください。

5.5.1 補足1

単位のSI接頭辞(SI接頭語)に関連した変換は、次のようにできます。

%reset -f
x = 42195 # 42195(m)
print(f'{x:,}(m)は、{x*1e-3}(km)です')
print(f'{x:,}(m)は、{x/1000}(km)です')

5.5.2 補足2

f文字列は、print関数の引数として使用することが多いですが、独立して使用することもできます。

%reset -f
month = 4
day = 27
date = f'{month:02}{day:02}日'
print(f'こんにちは。きょうは{date}です。')

5.6 丸め誤差

第03回の情報の授業で学習したように、10進数表記では有限小数となる数値が、2進数表記では無限小数になることがあり、また、コンピュータのメモリ (記憶領域) が有限であることから、コンピュータで小数を扱う場合は 丸め誤差 が生じます。これは Python でも同様で、特に金融計算を扱う場合には、特に注意する必要があります。

%reset -f
x = 2.4 - 2.25   # 0.15
print(f'x = {x}')

中級者向け: decimalモジュール

decimalモジュール を使用することで、計算に「0.1」や「0.2」を含む場合でも誤差なく正確な計算ができるようになります。ただし、通常の計算にdecimalモジュールを使うことには相応のデメリットがあります (考え、調べて、検証してみましょう)。

%reset -f
from decimal import Decimal
x = Decimal('2.4')-Decimal('2.25')
print(f'x = {x:.20f}')

5.7 べき乗の計算

べき乗の計算には、** 演算子を使用します (Excelではべき乗の計算に ^ を使用します)。

%reset -f
a, b = 2, 6  # a=2 と b=6 を1行で記述
x = a ** b   # aのb乗(2の6乗)を計算
print(x)

上記では変数を経由していますが、次のように変数を使わずに同じ出力を得ることもできます。

%reset -f
x = 16 ** 2
print(x) # => 256
%reset -f
print(16**3) # => 4096
%reset -f
16**4 # => 65536

また、** 演算子を使用することで平方根や、3乗根、4乗根を求めることもできます。

\[ \sqrt{256} = 256^{1/2} = 256^{0.5} = 16\]

%reset -f
a, b = 2, 0.5
x = a ** b   # aのb乗。0.5乗=1/2乗=平方根
print(x)

6 宿題

ここまでの「演習①」「演習②」に加え、次の「演習③」を今回のノートブック上で取組め。どうしても意欲が湧かない場合は、2時間を費やしてできるところまでもOKです (もちろん、何時間かけてもOKです。将来への投資です)。

どうしても解決できないことがあれば、LINEでスクリーンショットと共に質問もOKです。

6.1 演習③

Pythonを利用して、次の各問いの答えを求めよ。また、求めた答えが正しいものであることを、何らかの方法(手計算、関数、電卓アプリ、Excel、別ロジックのPythonプログラム、別のプログラミング言語など)を使って検証せよ。

6.2 演習③-1

(「情報2」の講義ノート p.25 より) CPUのクロック周波数が2.1GHzのとき、そのクロック周期が何秒になるかを計算せよ。なお、X.XXXe-XX のような指数の形式による出力と、SI接頭語 ( μs or ns or ps ) を用いた XXXX(ps) のような形式による出力を得ること。

6.3 演習③-2

(「情報2」の講義ノート p.30 の脚注より) 電気信号が伝わる速さは「光速」とほぼ同じで約 \(3\times 10^{8}\) (m/s) である。CPUのクロック周波数が \(2.8\)(GHz) のとき、そのクロック周期に相当する時間のなかで電気信号が進む距離を XXX.X(cm) の形式で出力せよ。小数点以下は1桁で答えること。

6.4 演習③-3

次の16進数を2進数と10進数に変換せよ。

\[(1)\ \ \ (\mathrm{FFFF}\ \mathrm{FC00})_{16}\] \[(2)\ \ \ (\mathrm{1000}\ \mathrm{0101})_{16}\]

6.5 演習③-4

次の2進数を16進数に変換せよ。

\[(1)\ \ \ (0011\ 0101\ 1010)_{2}\] \[(2)\ \ \ (1001\ 0110\ 0011)_{2}\]

6.6 演習③-5

現在までに学習した「物理」や「数学」、その他の「専門科目」に関する問題 (主に計算問題) をテキストセルに記述し、それを Python を使って解け。