Python* での苦い経験

同カテゴリーの次の記事

インテル® Xeon Phi™ 向けのコードの現代化

この記事は、インテル® デベロッパー・ゾーンに公開されている「I Was Just Dipping in a Toe and Got Bit by Python」の日本語参考訳です。


私は、ヘルス & ライフ・サイエンス・グループに所属していたときから Python* を少しずつ学んできました。これまでは、Linux* システムにデフォルトでインストールされる Python* 2.6 (Py2) を使用してきましたが、インテル® Distribution for Python* のリリースを機に Python* 3 (Py3) に移行することにしました。

私が取り組んでいたコードの 1 つは、三角形の面積を計算するものでした。三角法を覚えていれば (あるいは Web で検索すれば)、三角形の面積は底辺 × 高さ ÷ 2 であると分かります。私が取り組んでいた問題では、2 等辺三角形を使用する必要がありました。そこで、面積の計算には、等辺のいずれかではなく、底辺を使用することにしました。そうすることで、2 等辺三角形の底辺の半分を 1 辺とし、等辺を斜辺とする直角三角形を形成できるからです。さらに、すべての辺の長さは整数値でなければならないため、ピタゴラスの定理を使用して三角形全体の高さを計算することにしました。そして、直角三角形の 3 辺の関係をテストするため、次の関数を記述ました。

>>> def pythagorean_triple(c, a, b):
...        return (c*c == (a*a + b*b))

直角三角形の底辺と斜辺は分かっているため、上記の式を使用して高さを計算することにしました。斜辺の 2 乗から底辺 (2 等辺三角形の底辺の半分) の 2 乗を引き、差分の平方根を計算し、結果の小数点以下を切り捨てて整数値を得ました。最後の処理は、2 等辺三角形の面積が整数かどうかを確認するためのものです。高さが小数点値の場合、ピタゴラスの定理は成立しないため、2 等辺三角形の面積は整数値になりません。(一般には、整数値の底辺を乗算すれば整数値になるため、これは必ずしも正しいとは限りません。しかし、2 等辺三角形の斜辺の長さには、まだ説明していない特別な関係が存在するため、2 等辺三角形の面積が整数値にならないことは分かっていました。)

>>> e = 126500416/2
>>> e
63250208
>>> d = int(math.sqrt(126500417*126500417 - e*e))
>>> d
109552575
>>> pythagorean_triple(126500417, e, d)
True

これは想定どおりの結果です。Py3 で同じコードを実行したところ、次のようになりました。

>>> e = 126500416/2
>>> e
63250208.0
>>> d = int(math.sqrt(126500417*126500417 - e*e))
>>> d
109552575
>>> pythagorean_triple(126500417, e, d)
False

私はインタラクティブに実行していたので、ピタゴラスの定理をテストする前に、’e’ [行 3] の出力値に困惑しました。偶数 (126500416) を 2 で割っていることが分かっていたので肩をすくめるしかありませんでした。出力値は浮動小数点値ですが、実際の値は算術的に整数値と等しいものです。Py2 の出力とは異なる、そして私が説明してきた三角形とも異なる結果が最後の行に出力されたとき、私は言葉がありませんでした。

最初、私は Python* インタープリターまたはランタイムの不具合を見つけたのかと思いました。しかし、すぐに自分のコードに何らかの問題がある可能性が高いと考え直しました それぞれの実行でコードに問題はありませんでした (実際に、1 つ目の Python* セッションから 2 つ目の Python* セッションにコードをカットアンドペーストしてみました)。次に、私よりも Python* プログラミングに詳しい人達に聞いて回りました。

答えはすぐに分かりました。Py3 では、Py2 から除算演算子の定義が変更されていたのです。具体的には、1 つのスラッシュ (/) 演算子が、オペランドに関係なく浮動小数点値を計算する “true division” (真の除算) に変更されました。Py2 では、オペランドがどちらも整数値の場合、結果の整数部分が商とされました (切り捨て除算)。浮動小数点値の商を得るには、いずれかのオペランドが float (浮動小数点値) である必要がありました。(これは私が慣れ親しんでいる少なくとも 1 つの別のプログラミング言語でも同じで、ほかのプログラミング言語の算術演算に対する考えを改めるものになりました。)

Py3 では 2 つのスラッシュ (//) 演算子を使用すると、整数値の商が得られます。つまり、整数値の辺の長さが必要な場合は、// 演算子を使用すべきです。’e’ の出力値が浮動小数点値であったときに、このことに気付くべきでした。この経験は、アプリケーションで想定外の動作に驚く前に、使用するツールについてよく理解することの重要性を認識する良い機会となりました。問題が生じる可能性のあるすべての詳細を知る必要はありませんが、今回の Python* バージョン間の変更のように明白なもの (そして、オンラインで詳しくドキュメント化されているもの) は把握しておくべきです。今後このようなことがないように、Python* 3 のテキストをもっとよく読んでおこうと思います。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事

  • コード変更なしで OpenStack* Swift のパフォーマンスを 2 倍に向上コード変更なしで OpenStack* Swift のパフォーマンスを 2 倍に向上 この記事は、インテル® デベロッパー・ゾーンに公開されている「Doubling the Performance of OpenStack Swift with No Code […]
  • インテル® VTune™ Amplifier XE を利用した Python* コードの高速化インテル® VTune™ Amplifier XE を利用した Python* コードの高速化 この記事は、インテルの The Parallel Universe Magazine 25 号に収録されている、インテル® VTune™ Amplifier XE を利用して非常に低いオーバーヘッドで Python* コードのプロファイリング情報を得る方法に関する章を抜粋翻訳したものです。 インテル® VTune™ […]
  • Python* プロファイルPython* プロファイル この記事は、インテル® デベロッパー・ゾーンに公開されている「Python* Profiling」の日本語参考訳です。 Python*/C/C++ が混在したコードのパフォーマンス解析機能 - ベータ 混在したアプリケーション・コードの隠れたホットスポットを検出 インテル® VTune™ […]
  • インテル® Distribution for Python* の紹介インテル® Distribution for Python* の紹介 はじめに Python* (パイソン) は、現在ディープラーニングで注目を集めているプログラミング言語です。ディープラーニング用のライブラリーやフレームワークが Python* は豊富ということもあり、ディープラーニング = Python* と認識されてきているように感じます。C […]
  • インテル® Distribution for Python* の既知の問題インテル® Distribution for Python* の既知の問題 この記事は、インテル® デベロッパー・ゾーンに公開されている「Intel® Distribution for Python* Known Issues」の日本語参考訳です。 インテル® Distribution for Python* は、次の環境ではまだ不安定でクラッシュする可能性があります: OS X* […]