先日は、
■ 文字列の取り扱い(1) 【 Python 3.10.1 】
の中で文字の取り扱いについて書きました。Pythonでは配列の制御が出来るので、リストの形で記録したデータを昇順や降順で並べる事が出来ます。
この時にを使う事になりますが、 【 [ ] (インデックス) 】の中に数値で値を指定できますが 【 : (スライス) 】 を使う事で場所だけでなく、 昇順と降順の指定が出来るようになります。
また、 【 len 】 を使うとデータの長さを使用できるようになるので、
のような処理を行うと、
のような事もできます。また、現在は中学校の数学でも箱ひげ図が登城しますが、これについても
のようなコードを書くと、
のように出せます。Pythonの場合だと、matplotlibが箱ひげ図に対応しているので、それを使った方が簡単な気がしますが、こうした計算も行えるようになっています。
先日は、関数についても書きましたが、その中で
のようなコードを書きました。これを 【 F5 】 で実行すると
のようになりますが、コンソールで実行すると、
■ 一次関数の問題を出してくれるプロフラム
のようになります。
先日は、配列と関数について書きましたが、今回は、変数について書こうかなと思います。
P ythonを使う
Pythonですが、
のようにコンソールで開くこともできるのですが、この場合、
のように対話式の操作が可能になります。そして、用意されているライブラリであれば、
のように読み込んでそのまま実行する事ができます。例えば、
のような感じで問題がない場合にはそのまま入力が出来るようになっています。この後に、
のように関数を記述して処理を実行する事になります。ちなみに、これを実行すると、
のようにコンソールが初期化されます。これとは別に、統合環境としてIDLEが用意されており、実行すると、
のようにコンソールが出てきますが、メニューから
のように 【 NEW FILE 】 を選択すると、
の世にコードエディタが出ます。ただ、
のように一つの画面内に複数のウインドウが表示されてしまいます。
R言語のGRuiのようにレイアウトが出来る物もありますが、Pythonではそうなっていないので、
のように、画面内でウインドウをを選んで、
【 WINDOWS 】キー + 【 カーソル 】キー
で画面にウインドウを配置する事になります。右を選ぶと右半分に配置され、左を選ぶと左半分に配置できるので、
のような感じでウインドウを分割して配置すする事が出来ます。
これは、WIDNDOWS 10での標準機能になりますが、1つの画面内に複数のウインドウを表示できるようになっています。
また、コードエディタでは、
のようにOptionの項目から、 【 Show Line Number 】 を選択すると
のように行番号が表示されるようになります。
■ プログラムを実行する
Pythonでは、プログラムを実行する前に必ずソースコードを保存する必要があります。
のようなコードを書いて実行する場合、
のようにメニューから 【 Sava As... 】 を選ぶ方法もありますが、
【 CTRL 】 + 【 SHIFT 】 + 【 S 】
の組み合わせでも 【 新規保存 】 ができます。その後、
のように 【 Run Module 】 を実行すると、
のようにコードが実行されます。コマンドプロンプトだと、
のようにPythonと入力するか、python 3 とニュ力して実行すると、
の表記が出て、Pythonになるので、
のようにファイルを指定して実行すると、
のようにコンソール上で実行されるようになります。
関 数にデータだけを格納する
関数は、 【 処理を格納した構造体 】 で、
■ 引数
■ 処理
■ 戻り値
を実装できます。関数の場合、
■ 引数の無い関数
■ 引数と戻り値の無い関数
■ 全てが揃った関数
を作る事ができますが、これとは別に
【 戻り値のみの関数 】
と言うのも作れます。これを使うと、 【 値だけを取得できる 】 ので、
【 変数を外部参照する 】
事が出来るようになります。しかも 【 リストの外部参照 】 ができるので定数の集合であれば、ファイルとして確定したデータを外部から読み込んで使用する事が出来るようになっています。実際にコードを書いてみると、
のような感じになりますが、
のような結果を得る事が出来ます。
引数の仕様ですが、値の 【 , 】 で開業すると、
のようになり、実行すると、
のようになりますが、これを引数単位で改行すると、
のようになりますが、この状態だとエラーが出てしまいます。
この2つですが、
のような違いがあるので、前者の場合インデントがあるのでreturnの中の処理として判断されていますが、後者については、全く別の処理になっている(関数と同じ位置なので回数の外の扱いになっている)ので
エラーが出ています。
文 字列の変換
データを扱う場合、文字列と数字を使いますが、用途に応じて型を使い分ける事になります。
■ Input()による影響
データの型の変換ですが、変数を使う場合には目的に合った型にする必要があります。これは、 【 1 + 1 】 と言う物が解りやすいのですが、
のように変数の型の違う物を用意して、同じように 【 + 】 を使った場合、数値と文字では扱いが異なるので、
のように異なる結果が出ます。記述が厳密なプログラミング言語だとこんな感じの型の自動判別はしてくれませんから、C言語やC++の場合だと、変数の型を宣言する必要がありますから、この事例だと、
■ 整数 : int型
■ 文字 : str型
のようになりますが、この二者で 【 + 】 を使ったとしても処理が異なり、
■ 数値 : 計算
■ 文字 : 結合
と言う違いがあります。このように、
■ 数値 + 数値
■ 文字列 + 文字列
の場合は、 【 + 】 で対応できるのですが、これが、文字列と数値のように型の違う物を表示する場合には記述が異なり 【 , 】 を使う事になります。
のようなコードを書いて実際に実行すると、
のように前者では、 【 文字列 】 と 【 演算結果 】 が表示されており、後者では文字列が結合されています。
方が混在する時には記述が変わってしまうのですが、Pythonでは標準入力としてinput()があります。これを使って、
のようにすると計算が出来そうですが、input()では文字列を取得するので、
のようになってしまいます。その為、名前などの文字を入力する際にはそれでいいのですが、計算をするプログラムだとこの状態では使用できません。そこで、
のように型を変えると、
のように計算できるようになります。変数には宣言の方法と型の変更による使い分けが出来る仕様になっていますが、型の違いで結合と
■ 文字列を式にする
プログラミング言語の学習をすると初期の段階で計算式の作り方は学習しますが、この方法だと、 【 電卓 】 のような処理が全く分からない場合があります。式を入れると答えが出るようなプログラムは作れますが、
【 数値 】 + 【 演算記号 】 + 【 数値 】
というような入力で計算するような物は作れません。この場合、別の処理が必要になるので、 【 式のデータをもとに評価結果を出す 】 必要が出てきます。
データの場合、前述のように
■ 整数 : int型
■ 文字 : str型
となりますから、 【 計算式 】 については、
の事例で言うと前者になります。つまり、この条件で考えると、文字列の結合は出来ても、演算記号の入った式の計算は出来ないので、計算結果を出す場合にはそれに準じた処理が必要になります。Pythonでは、 【 eval() 】 を使う事で、この処理が出来るようになっています。
■ eval()
文字列を式として評価する場合に使用できる関数。
【 書式 】
eval('式として評価する文字列')
と言う形で処理を行う事が出来ます。その為、
のようなコードを書くと、input()で文字列を取得できるので、これで式の部分が出来るので、これに 【 = 】 の文字列を結合と式ができます。
このままでは 文字の結合だけなので、演算記号を含めて乳慮kすいた部分を変数化してeval()で評価結果を出力すると式の計算結果が出るので、これを変数野中に格納します。eval()は関数なので、引数を代入した結果を変数に格納して使う事になりますが、この状態にすると、
■ 式
■ 解
を用意できるので、それを入力後に表示すると式と解を表示できるようになります。単体だと違う式との評kをするのが煩雑になるので、今回は、forループの中に含めていますが、これを実行すると、
のように数値と演算記号の入力によって式を作って計算をする事が出来るようになります。つまり、電卓と化を作る場合は、こうした評価結果を使っている訳ですが、項の数が増えた時の演算方法は最初からしkを実行すると、式の解とは乖離した値が出て来るので、式をそのまま打ち込んで適正な計算結果になるプログラムの場合、文字列の解析をするような仕組みも実装する必要があります。
通常の電卓は、メモリーを使って計算式を項の加算の式の状態にする必要がありますが、関数電卓だと括弧が使えるので、加算とそれ以外に分けて式を構築しなおして計算する事ができます。
小学校低学年で 【 四則演算の組み合わさった式の計算方法 】 を学習するので、ループ処理で買いが出る構造物と単体の処理の違いについては学習する(ので、乗除算と加減算は全く別の構造体担います。なので、小学校だと、足し算と引き算の作りと掛け算と割り算の作りが違う事と、組み合わさっている場合にどう言った処理をすればいいのか?も学習する事になりますから、日本の義務教育を受けている場合だと、四則演算が組み合わさった式については、計算方法が存在する事については、小学校低学年レベルでクリアしている内容になります。)ので、手計算で正しい式の構築をした場合と、式の順番通りにフラッシュ演算のような感じで計算すると全く違う結果になるというのは殆どの人が理解している内容ですが、電卓の場合だと、数値を打ち込んで演算記号(及び、=)が入力された時に計算結果を出してしまう作りですから、演算結果に別の式が加わって演算を繰り返していくようなフラッシュ演算のプログラムのような仕組みになっています。その為、正しい解に行きつくためには、
【 人力で式を再構築する必要がある 】
訳です。こうした計算における必要な知識と電卓での計算能力を高める為の検定として 【 電卓検定 】 と言うのがありますが、この計算については、 【 式の理解と計算できる形への再構築 】 をする事が必要なので、 【 計算その物が出来ないと式の変形が出来ない 】 ので、正しい解に行きつかないようになっています。つまり、機材の構造上 【 電卓を使うとしても、小学校レベルの四則演算の計算方法を知らないようだと正しい計算結果に行きつかない 】 ので、 【 電卓があれば算数が出来なくても計算が出来る 】 というような内容については 【 ただの間違い 】 と言う事になります。
電卓についても、 【 ロジックとラッチで動いている構造物 】 ですから、 【 処理の仕組み 】 が存在します。その為、桁の処理でシフトレジスター回路とか桁の繰り上がりの処理でキャリー先読み回路とかも使用されていますが、基本的な処理としては、前述の通りで、
【 入力値及び演算結果に処理を追加する 】
と言う仕様になっており、その式が完成した後に、演算記号が入ると演算が発生するような仕様になっています。
その為、構造からすると、 【 3 + 2 * 3 + 4 】 のような式がおかしな結果になります。中学校になると1年生の数学の中で 【 項 】 を学習しますから、この式が、 【 a + ab + c 】 と言う構造体である事が解るので、この式の計算方法は、 【 3 + ( 2 * 3 ) + 4 】 になるので 【 3 + 6 + 4 = 13 】 という風に簡単に答えを出せるはずですが、電卓の場合は、 【 フラッシュ演算 】 なので、
【 a + b * c + d 】 を順番に処理していく
と言う恐ろしい仕様になっています。つまり、
【 3 + 2 = 5 】
【 5 * 3 = 15 】
【 15 + 4 = 19 】
と言う感じです。つまり、 【 19 】 と言う現実と乖離した数値が出てしまっている訳です。つまり、1.46倍も大きな数値になっていますから、訳5割増しの謎の数値が出てしまうわけです。当然、この状態を計算しているとは言いませんから、機材があれば無知でもどうにかなるという妄言を耳にしても鵜呑みにしない方がいいのは確かです。と言うのも、 【 機材が出来るというのは人の言動でしかなく、システム自体を理解して核にしている訳ではない 】 ので、事実確認をして検証しないと解らない事の方が多いです。とりあえず、今回の式のように手計算(と言うか、暗算レベル)で出来る事を電卓を使って間違うというのは相当末期な話ですし、機材に依存して間違うのはさらに酷い内容ですから、そうならない為にも仕組みを理化して使うこなす必要があります。
Pythonで実際にこの計算をしてみると、
のようなコードで比較ができます。ちなみに 【 \n 】 は改行記号です。これを実行すると、
のようになるので、こうした計算については対応しているようです。計算機を作る場合、 【 処理と結果 】 を最初に確認しておく必要がありますが、これと同時に行っておく必要があるのが、丸め誤差の影響になります。
コードを書く際には実行結果が正しいのかを事前に知っておく必要がありますから、今回のような物も電卓と同じような構造なのか演算記号で判定を入れて式を判断して処理をしているのかを事前に知っておく必要がありますが、これと同時に知っておく必要がある物として小数点数の取り扱いがあります。コンピューターの世界では十進数の小数点数と言う概念がないので、計算をすると意図した結果にならない場合があります。これを 【 丸め誤差 】 と言いますが、こうした処理はコードの結果眼があると出ますし、スプレッドシートの計算については解を正しく取得できるような構造にしていないとおかしな状態になります。丸め誤差については、
の中で触れていますが、スプレッドシートでも出ます。ちなみに、誤差の中には
■ 丸め誤差
■ 切り打ち誤差
■ 情報落ち
■ 桁落ち
などがあります。その為、使用している言語で処理を行った場合に、どう言った挙動になるのかを事前にテストをして傾向から対象を行ったうえで、ごく当たり前な処理が行えるコードを書くことになります。
■ 計算の順番
先ほどの事例では影響が出ませんでしたが、こうした処理が出来ると、簡単な数式を使った物だと対応できそうですから、BMIの算出のような物も簡単なコードを書けば算出できるようになります。
のようなコードを書いた場合、
のように数値を入れて判定すると
のように相当おかしな数値が出てきます。これは、演算の優先順位によるものですが、これはC言語で行った場合にも発生します。プログラミング言語には有線関係と言うのがあって、
■ 【 * 】 や 【 / 】 は 【 + 】 や 【 / 】 より
優先される
■ 【 = 】 の優先度は低い
■ 同じ優先度の場合、左側が優先される
■ 括弧内が先に計算される
と言う仕様なので、1+2*3が9になるような事はありません。この辺りは電卓よりも賢いアルゴリズムになっているのですが、BMIの式をこのコードのように書くと、エラーは出ないのですが、おかしな結果が出てしまいます。この条件で考えると、除算処理が先に行われているので分母が崩壊するような式になっているので破綻しているので、分母を正しい状態にすると治ります。
のように式を再構築して 【 正しい分母 】 にすると、
のようにBMIが表示されるようになります。簡単な式の場合、変数の入力から割り出せるものが多いので、それを元に算出する事が出来ますが、計算をする上では、演算の法則性を知って式を作らなければなりません。
計算をする場合、こんな感じの簡単な式でも対策をしないとおかしな結果になるのですが、二次関数の解の公式を適応した場合でも桁落ちでおかしな結果になる場合もありますし桁が足りない場合も出てきます。その為、式をそのまま追加しただけだと問題が出る場合があります。浮動小数点数ではそんな感じの事が発生しますが、これとは別に、
■ 代入時の桁あふれ
■ 計算時の桁あふれ
のように指定した型の範囲を超えた桁になった時におかしな結果になる事もありますし、
■ 情計算著中の小数点数の切り捨て
■ 浮動小数点数型の誤差
によってもおかしな状態になる場合もあります。また、
■ 異なる方の比較
でもおかしな結果になる場合があるので、エラーが出ない状態だとなんでも正しく動くという訳ではありません。むしろ、今回のBMIのコードのように 【 計算が走ってしまって乖離した値が出る 】 ほうが問題が多く、これを参照して複数の物が動く場合だと問題は深刻になりますから、エラーが出る程度だと大した問題ではなく、修正が用意なレベルの部類になります。
桁のオーバーフローと言うのは、型には記録できる範囲があるのですが、これは型のビット数で決まています。
C言語だとcharのような8bitから、long longのように64bitまで用意されていますが、使用するデータの数はこのビット数で決まっています。とは言っても、バイナリで値を扱った時にはどの言語も同じで、最上位の1桁目は符号で使用している(ので、数値の二値だけでなく桁を1つ消費する事で2bitの処理をして数値を扱っています。)のですが、値を代入する際には、この型の用意されているビット数内に収めて格納する必要があります。その為、8bitに収まる物だと、C言語だとchar型で大丈夫なんですが、これが9bit以上になると、変数で用意しているビット数の範囲外は格納されないので、 【 上位数桁の桁の切り捨て 】 が発生します。これが 【 桁あふれ 】 です。
その為、代入する値(リテラル)のデータ量を超えるビット数のある型を指定しておくtこうした問題は発生sないので、整数の型だとintを使えば先程の条件は回避できます。C言語の場合だと、char以上、int未満の物としてshortも用意されていますが、intで対応してみて無理だとlongやlong longを使う事になります。
こうした処理は、変数の代入時だけでなく、その値よりも巨大になる演算結果でも発生しますから、出力される演算結果の値がどの程度のサイズになるのかを事前に確認してそれよりも大きな値にしておく必要があります。計算時の桁あふれの場合、巨大な数値だと符号に桁た到達して負の値が出る事もありますから、型の選択が需要になります。
また、整数で計算すると整数の解しか出ないような条件だと、型を浮動小数点数型にしておかないとダメなので、C言語とかだと小数点数で桁が増える条件だと、floatやdoubleを使う事になります。
浮動小数点数でも誤差が出る事があるので、桁数分の整数をかけ合わせて整数にしてしまい、その状態で計算をする事で小数点数で発生する誤差を抑える方法もあります。つまり、
■ 小数点数に10のn乗の数値を描けて整数化
■ 演算処理
■ かけ合わせた値で割る
と言う処理をしておけば整数の割算の結果になるので浮動小数点数で発生する誤差の発生を回避できます。
こうした理由から 【 型 】 を指定して制御する必要がある言語が多いのですが、Pythonでも計算をする場合でも誤差でおかしくなることがあるので、どう言った原因でそれが発生居ているのかを確認する必要があります。
Pythonで小数点数を使う場合ですが、
値が極めて近い数字同士を引き算すると情報が失われ、
精度が落ちる
事があるので、そうした場合には、何かしらの処理を実装する必要があります。
小数点数の誤差の丸め誤差はroundで丸めると解消できるのですが、ループとかで小数点数の加算処理を行うとおかしなことになる場合があります。例えば、
のようなコードを書いた場合に実行すると、
のような結果になります。これは加算のループ処理なので、小数点数の乗算処理の結果を出力する物になりますから、処理の結果として、小数点数以下の誤差が出ています。これが、丸め誤差による影響になります。この場合、整数の結果しか出ないので、整数にしてしまえばいいので答えは簡単で、 【 四捨五入 】 をするだけで対応できます。この場合、mathモジュールを使う事になりますが、
のようにして、raund()関数の中に変数を入れて処理をすると
のように適正な値にする事が出来ます。小数点数のループの場合、表示をしていくような場合だと、整数を使って指数で桁を下げて表示すると、値は安定するので、コードの書き方も整数のカウンターとは少し違った物になります。