二点を通る直線の式の先にある技術 第2回

リンクは記事が公開され次第随時更新します。

第2回では二点を通る直線を求めるプログラムを作ります。今後の記事でも同じプログラムを使ったり改造したりする予定です。なるべくわかりやすく書きます。言語はpythonです。

プログラムで書く利点

人間が求めるのに比べて、プログラムを書く利点は以下のことが挙げられます。

  • 高速に求まる
  • 正確に求まる
  • 大量に求まる
    コンピュータが計算するので高速に求まります。ややこしい割り算でも関係ありません。また、プログラムがあってさえいれば正確に求まります。そして大量に求めることができます。100回でも1000回でも疲れうことなく高速に正確に求めることができます。この利点は後々役に立つことになります。

二点を通る直線を求めるプログラム

二点を通る直線を求めるプログラムを書くというのは、以下の入出力を持つ関数を作成することになります。

  • 二点の座標を入力したときに
  • 傾きと切片を出力する
    入力される二点はp1=(x1, y1)とp2=(x2, y2)とします。すると傾きと切片は以下のように求めることができます。
def calc_slope_intersept(x1, y1, x2, y2):
    a = (y1 - y2) / (x1 - x2)
    b = y1 - a * x1
    return (a, b)

プログラム全体として以下のように記述します。

def calc_slope_intersept(x1, y1, x2, y2):
    a = (y1 - y2) / (x1 - x2)
    b = y1 - a * x1
    return (a, b)

if __name__ == "__main__":
    a, b = calc_slope_intersept(1, 2, 3, 4)
    print("傾き:", a)
    print("切片:", b)

これは点(1, 2)と点(3, 4)を通る直線の傾きと切片を表示するプログラムです。これは下の図のようになり、傾きは1切片も1になります。

点(1,2)と点(3,4)を通る直線

プログラムを実行すると以下のような出力になり、ちゃんと動作しているように見えます。

傾き: 1.0
切片: 1.0

私の紹介した開発環境で動作させたとき、出力結果が文字化けしてしまうときは、以下のスクリーンショットのようにchcp 65001と入力すると改善されることがあります。このコマンドでは、ターミナルの文字コードをUTF-8に変更しています。

ターミナルでchcp 65001と入力

例外の取り扱い

このプログラムで大体の問題は解くことができますが、二点のx座標が同じで傾きが無限大になってしまうケースを入力すると以下の図のようなエラーが発生します。

ゼロ割エラー

これはゼロ割エラーです。エラーの対処方法は様々あります。そもそも関数を求めるという問題設定であれば、同じx座標である2点を通る直線の関数は求められません。そのような旨のエラーメッセージを出してプログラムを終了させるでもよいでしょう。数値計算をするときの常套手段としては、分母にすごく小さい値(0.00000001等)を足しておいてエラーとはせずに近似計算を行います。この場合、傾きは無限大ではないですがものすごい大きい値になります。今回のケースでは図示することを目的とし、傾きが無限大であることをfloat('inf')で示し、その時の描画処理を場合分けすることで対処します。以下に今回作成したプログラムの全体を記述します。

import matplotlib.pyplot as plt

def plot_line(x1, y1, x2, y2, a, b):
    r = 5       # 描画範囲を設定(-5から5までを描画、後で変えるかもしれないので上のほうに記述)
    rr = r + 1  # 計算範囲を設定(描画範囲±1まで計算する)

    if a == float('inf'):  # 傾きが無限大のとき
        plt.plot([x1, x2], [-rr, rr])  # 直線を描画
        plt.scatter([x1, x2], [y1, y2])  # 点を描画
    else:
        plt.plot([-rr, rr], [-a * rr + b, a * rr + b])  # 直線を描画
        plt.scatter([x1, x2], [y1, y2])  # 点を描画

    plt.xlim([-r, r])  # x描画範囲を指定
    plt.ylim([-r, r])  # y描画範囲を指定
    plt.xticks([i for i in range(-r, rr)])  # x罫線を指定
    plt.yticks([i for i in range(-r, rr)])  # y罫線を指定
    plt.grid()  # 罫線を描画するよう設定
    plt.axhline(y=0, color='k')  # x軸を描画
    plt.axvline(x=0, color='k')  # y軸を描画
    plt.show()  # プロットを表示

def calc_slope_intersept(x1, y1, x2, y2):
    if x1 - x2 == 0:
        return (float('inf'), None)  # 傾きが無限大のとき
    a = (y1 - y2) / (x1 - x2)
    b = y1 - a * x1
    return (a, b)

if __name__ == "__main__":
    a, b = calc_slope_intersept(3, 1, 3, 3)
    plot_line(3, 1, 3, 3, a, b)
    print("傾き:", a)
    print("切片:", b)

わかりやすさのためにたくさんコメントを入れていますが、実際に使うプログラムにはここまで自明なコメントは入れません。また、なるべくコメントも英語で表記するようにしましょう。calc_slope_intersept関数の中で、傾きが無限大になってしまうとき、float('inf')Noneを返しています。float('inf')はpython標準で無限大を表現しています。またその時の切片はないので、Noneとし、python標準で非存在を表しています。

次回

今までは既存の知識の復習とプログラム化を行いました。次回からいよいよこの概念を一般化し、機械学習・人工知能・AIの領域に踏み込みます。

コメント

タイトルとURLをコピーしました