教育」カテゴリーアーカイブ

micro:bitのタスクシステムを考察してみた

というわけで、なんとなく気になったので書いてみたくなったネタです。電子工作系と教育系を兼ね備えるものといえばmicro:bitな訳ですが、そのタスクシステムにちょっとした疑問があるので考察して+調べてみよう、というわけです。

 

MakeCode(Scratch)でmicro:bitのプログラムを作った時を前提とする

micro:bitで動くプログラムを作ることができるツールはいくつかあるわけですが、今回はMicrosoftのMakeCodeを前提としたいと思います。MuやらPython Editor for micro:bitやらあるのですが、小学校や中学校でも使えるレベルで、となると大半がMakeCode経由のような気がしますので、これで話をしたいと思います。

 

「ずっと(forever)」を何個も使うと一体どんな実行のされ方をするのか?

まずはこれを見てください。

 

MakeCodeである3つのブロックを使おうとしたときの状態です。見てわかるとおり「最初だけ」のように複数あると意味がわからなくなるものや「ボタン○○を押したとき」のように、入力の割り込みによって動くのものは1つしか有効にならないようになっています。これはわかります。

ところが、「ずっと(forever)」に当たるブロックを作ろうとすると上の図にあるように2個作ってもどちらも有効です。なお、基本的には何個でも有効になります。つまり、「すべて動作させることができる」という(プログラムをやったことがない人から見ると)不思議な現象が発生します。だとすると「Aをずっと繰り返す」「Bをずっと繰り返す」「Cをずっと繰り返す」を同時にしたいときに「A、B、Cの順にしてそれを繰り返す」のように無理に直列化して書かなくても個別に書いてよい、ということになるのでしょうか。これをちょっと見てみたいと思います。

 

次のように書くとどう実行されるのか?

というわけで、こういうプログラムを作りました。

「ずっと」ブロック×3と「ボタンAが押されたとき」の動作です。ちなみにこれはちょっとしたトリックがあって、「ずっと」のブロックの上下が0の出力と256の出力だと256の出力が下になるように配置しています。

で、これを(あくまでシミュレータ上ですが)実行するとこういう動きになります。

「0を出力」→「256を出力」→「512を出力」→「0を出力」→「256を出力」→「512を出力」→「0を出力」→…

つまり、「ずっと」のブロックを上から3つを順番に回しながらに実行しているだけ、となりました。ちなみにボタンAによる割り込みをかけてみたのですが、「ずっと」による実行順番は変わらず、という結果になっています。あくまでシミュレータ上ですのでオシロスコープなどで実機計測すると微妙に違うかもしれません。

これについてはある程度推測ができて、

  • 「ずっと」ブロックを使うとそれぞれがタスクとして独立に実行待ちキューに入る
  • 実行時間になると実行待ちキューの先頭にあるタスクが実行状態となり実行される
  • ブロックの実行が終了すると再度実行待ちキューの最後に入り待機状態となる
  • 割り込みは特別なタスク扱いとなり、「ずっと」のタスクが実行されていないときにチェックされて状態が確認されればタスクとして実行される

という動きになっているのではないか、というものです。で、これをチェックするために「このプログラムをPython(もどき)で表したもの」とタスク実行に関する説明書(のようなもの)を見て確認してみました。

 

このプログラムをPythonで表すと…

MakeCodeのPythonで表す機能を使ってプログラムを変換するとこうなりました。

def on_button_pressed_a():
    pins.analog_write_pin(AnalogPin.P0, 768)
input.on_button_pressed(Button.A, on_button_pressed_a)

def on_forever():
    pins.analog_write_pin(AnalogPin.P0, 0)
basic.forever(on_forever)

def on_forever2():
    pins.analog_write_pin(AnalogPin.P0, 256)
basic.forever(on_forever2)

def on_forever3():
    pins.analog_write_pin(AnalogPin.P0, 512)
basic.forever(on_forever3)

どうでしょうか。「ずっと」の3つのブロックがon_forever関数、on_forever2関数、on_forever3関数の3つとして定義され、basic.forever関数を呼び出して渡されています。このコードとシミュレータの動きから推測するとbasic.foreverの動きは「渡された関数を(無限実行をする)実行待ちキューに登録する」ものだと考えられます。リファレンスのbasic.foreverの説明ではforeverのループとeventのループについて少し書いてありましたが、この動作については明確には改訂ないような気がします。

 

タスク実行に関する説明から考察してみる

で、このforeverの動きや「バックグラウンドで実行する」とはどういうことか?を説明しているのが(直リンクは張りませんが)「The micro:bit – a reactive system」というところです。micro:bitのタスク実行について実行間隔やポーリング、タスクを並行(Concurrent)で実行する方法について、ボタンを押す、などのイベントがあったときにどう動くのか?といったことについて詳しく書いてありますので見てみるとよいと思います。プログラム、特に組み込み処理に関して詳しい人ならば読めると思いますが、今回の処理に必要な部分を読んでみると、

  • サブルーチン(この場合はforeverとして登録されるタスク)を登録するときには優先度がないタスクとして実行待ちキューに入る
  • 一時停止(Pause処理)がタスク上で発生したときに一時停止キューで時間待ちを行う
  • システムによりタスクが実行可能となったときは実行待ちキューの先頭にあるタスクを削除し実行状態に戻す
  • 実行終了するか一時停止時間が経過したサブルーチン(foreverタスク)は実行待ちキューの最後に戻す

と書いてあることから上の考察の大半は合っているのではないか、と思われます。

 

「ずっと」ブロック内の時間待ちについて

micro:bitの時間待ちのうち「一時停止」よる時間待ちは上の説明から「一時停止キューにタスクを移す」ことにより待ちを行っていますので一度実行状態から抜けることになります。そのため、別のforever処理や入力割り込みによる処理などがあればそれを実行する時間がとれることになります。しかし「whiteなどによる無駄ループを使った時間待ち」は上の説明からmicro:bitのタスクとして待ち状態や実行待ちには移らず実行状態のままになりますのでタスク切り替えがうまくできません。そのため、入力の検知などを行う時間で割り込みそのものは検知できるのですが、割り込み後に動かすルーチンは実行待ちキューに移されるだけとなり実行されない、ということになるかと思います。

これは特にforever関数で長い処理を実行するタイプのタスク+ある程度の反応速度が求められる処理だとちょっと厳しいことになるかと思いますのでロボット操作をやるときやある程度速い周期で処理する必要があるルーチンでは気をつける必要があるかと思います。そもそもタスクの切り替え周期もどれだけ出せるのか微妙なところですか。

 

単に教育用として簡単なものを作るだけなら知る必要はないが…

例えば自由研究などで複雑なプログラムを作り実行させるとうまく動かない、というときにこういうことが絡んでいる可能性はあるかな~という例でした。MicroPythonを入れる例だとこういう風に動くのかどうかはまた別の検証が必要そうなので今はしません。ADVゲームシステムなどで本体内に別のスクリプトシステム(Luaなど)を使うタイプだと似たような現象が発生するのでちょっと調べてみた、というところにしておいてください。はい。

 

 

micro:bitのプログラミングがある場所では動作しなくなる?

ちょっとmicro:bitのプログラミングに関していろいろとやってみる機会があったので使っていたのですが、その中で気が付いたこと。ほかのサイトでも書かれていますが、こちらでもちょっと触れてみたいと思います。この件は一部の環境の人にはとんでもなく刺さる問題になっています。

 

micro:bitの主要なプログラミングツール

皆さんが使うのは大体このあたり、ということで示しておきます。

Microsoft MakeCode for micro:bit (https://makecode.microbit.org/)

インターネット環境とブラウザでプログラミングできる環境として有名です。使おうと思えばAndroidでもiOS系でも使用可能です。その場合は作成したhexファイルをどうやって転送するのか、を考える必要があります。ちなみに2020年6月にバージョンアップしてv3になっています。そのため、いくつかのブロック(Scratch)が追加されていたり、対応言語が増えているなどかなりの恩恵があります。対応している言語は「Scratch」「JavaScript」「Python」です。Pythonの場合はパッケージ指定がいらないので作成にはもってこいかもしれません。しかしながら、このバージョンアップがある悲劇をもたらしています。それは後ほど。

Micro:bit offline App – MakeCode (https://makecode.microbit.org/offline-app)

こちらはインターネット環境およびブラウザが利用できない場合に利用可能な方法です。Windows10とMacOS対応です。インストールが必要なのが欠点ですが、v3ベースの開発環境が使えるので実験する量が多い人はこちらをインストールしてしまうのもありかもしれません。Windows10の場合はストアアプリから同様のものを手に入れることが可能です。言語はオンラインv3版と同様。

Python Editor for micro:bit (https://python.microbit.org/)

Pythonを使う、と決めているならこちらを使ってみるのもよいかもしれません。こちらの場合はMicroPythonで動かすことを前提にプログラムを組むのでMakeCode版とは微妙に作り方が違うことに注意が必要です。ファイル転送に関してもpyファイルおよびデータファイルを指定すればhexファイルにくっつけた形で転送可能です。プログラムのサイズに限界があるmicro:bitにとってはデータファイルが使えるのでうまく組めばMakeCode版に比べて規模を大きくすることが可能です。

Muエディタ (https://codewith.mu/)

Pythonのエディタです。こちらに付属するmicro:bitの転送ツールを使うとpyファイルおよびデータファイルを転送することができます。こちらもMicroPythonベースですので気を付けましょう。

Androidアプリ or iOSアプリ

スマートフォンしか手元にない場合はこれらのアプリを使って作成&転送ができます。転送方法はBluetoothで、micro:bit側を特殊な待機状態にしてペアリングし、プログラムデータを転送します。失敗するとPCからhexファイルの送り直しになるという救援が必要ですが、ちょっとした実験やPCが台数分確保しづらい学校環境などではこれをインストールしてもらって実行する、というのもありかもしれません。

 

MakeCodeのブラウザでIEのサポートが外れたため大変なことに

v3へとバージョンアップしたときにInternetExplorerのサポートが打ち切られました。これ自身はまあかなり古いブラウザので仕方がないのかもしれませんが、ちょっと問題になっているらしいのが「学校で使用できるブラウザとしてInternetExplorerが強制されていることが多く、サポートがなくなって使えなくなってしまう」というものです。学校の環境では自由にインターネットをさせるとまずい場面があるため、それの制限が必要なのですが、IEを使用させてEdgeを使用不可にしている、というパターンが多いようです。このため、プログラミング演習がちょっと厄介なことになっています。

 

回避策は…

学校環境を前提にしていくつかありますが、どれも微妙です。

・MakeCodeのv2版を使う

一応過去版が使用可能です。過去版はv2版でURLに直接「/v2/」を入れる必要がある、つまりhttps://makecode.microbit.org/v2/への直接リンクが必要で、入力作業がかなり面倒だったりします。まあ、ショートカットを使ってごまかすことはできそうですが…ほかにもv3版で追加されたブロックやPythonが使えないこと。さらに根本の問題としてMakeCodeのv2版の期限が2022年まで、ということであと2年後にはIEの制限が解けない限りは同じ問題が起こることになることです。管理ソフトを作っている人たち、この問題は早めに解決しておかないとそもそもIEで正常にアクセスができないサイトがだいぶできていて問題ですよ、と言いたい。G Suite関係もサポート外になりそうですし。

・オフライン版のインストール

PCへのインストールが可能ならばこれで避けることは可能です。しかもv3版になりますのある程度新しい部分まで使うことができます。問題点は「インストールが可能ならば」のポイントで、環境を変えてしまう等の理由で認められない場合には使うことができません。無念…。

・Android版やiOS版のアプリを導入したタブレットで行う

特にコード入力ではなくScratchによるプログラミングを行うことが前提となる小学生レベルならばこのほうが逆に簡単かもしれません。問題は必要となる台数を確保できるか、というところ。まあ、このコロナ禍の影響でコンピュータなどの導入計画が早まっていますのでアプリが導入できるならこちらもありかもしれません。相変わらず導入制限があるとうまくいきませんが。

ちなみに、実機転送を行わずにシミュレータのみで動作を見る場合はタブレットからMakeCodeにアクセスさせる、という手段をとることができます。タブレットの場合はブラウザがChromeかSafariになるはずですのでMakeCodeの制限は越えられると思います。

・ポータブル版のブラウザを授業毎に導入して終了後無効にする

ちなみにたいていの学校のPCはちゃんと環境復元ソフトがある(もしくは学習環境管理ソフト内に同等の機能があるはず)なので、先に起動させておいてブラウザだけ入れておく、終われば即シャットダウン、という形でごまかすことが可能な環境はあると思います。もちろん、これはPC管理のポリシー違反になる可能性が高いのでかなり危ない回避方法だといえるかもしれません。私も考えはしましたが多分使わないでしょうね…。

 

今年の回避策はv2版になるのかな…

まあ、たいていの学校は演習でmicro:bitを使う場合はこれになるのでしょうね。よほど込み入った演習をやる予定か、プログラミング演習でコードを用いる演習をしたくて、かつそのコードにPythonを選ぶ、という場合でもない限りは、ですが。一応JavaScriptもあるので、Pythonをやらなければならない理由がないのであればそちらで頑張ってみてください、ということになるでしょうかね。

 

「1.1の8乗は2より大きい」を何パターンで示せるか?

というわけで数学遊びです。範囲としては数Ⅰ+数Aの知識でいけるのでそのあたりのテスト問題とかに出そうだな~ということでやってみています。証明が面倒になるものも含まれていますので気になる高校生の人は見てみるとよいと思います。なお、この記事を書く前にどうせならWindowModePatchの記事とかサーバーの更新の記事とかを入れておけば面白かったかな~と思わなくもないのですが、Twitterに書いたのでこちらを先にしました。

 

正式な問題はこの形

Twitterにもつぶやきましたが問題を解く前に意図を確認するために書いてみます。

Q. 1.1の8乗は2より大きいことを示せ。ただし直接計算を行う場合は正確に行うこと。また累乗の数の大小関係は証明されていないものとする。

実は問題が微妙にいやらしいのが面白いところ。これが例えば「1.001の750乗は2より大きいことを示せ。」という問題であれば解法は限定されるのですが手計算できるところに押さえられているのがミソです。そのために「直接計算を行う場合」の注意書きを入れてあるわけです。そして最後の意味は「概算の形で計算したいなら累乗の大小関係について証明した上でやりなさい」という意味をいっています。この部分は解答を見た方が意味がわかると思います。

ちなみにこの問題の形は自然対数の極限を考える段階で現れる問題の変化系となっていいます。そのため、その部分に入る前に宿題として出しておいて…ということも考えられる問題という意味も含まれています。

 

私が考えた解答は以下の3パターン

一つずつ紹介していきます。

直接計算パターン

A1. 値を直接計算して求める。

ちょっと面白いのが4乗までであればパスカルの三角形を考えればよいので何も考えなくても計算できるけれども5乗以上となると手計算では難しくなるところですね。これを考えた人は最後まで間違わずにできたでしょうか。(「直接計算を行う場合は正確に行うこと」に注意)

 

間接計算パターン

概算の形で計算するものです。問題文より累乗の数に対しての大小関係を証明した上で行います。

A2. 累乗の数に対する大小関係として以下の命題を証明する

Th2. となるa,bと自然数nに対して

Pr2. 数学的帰納法を用いる。

n=1のときはa>bとなり仮定より満たされる。を仮定すると

よりとなり

よって数学的帰納法より題意は示された。

 

A2.1 1.12 = 1.21 よって 1.18 > 1.24, 1.22 = 1.44 よって 1.18 > 1.422, 1.422 = 2.0164 よって 1.18 > 2.0164 > 2

A2.2 √2 = 1.41… よって 2 < 1.422, √1.42 = 1.19… よって 2 < 1.204, √1.20 = 1.09… よって 2 < 1.18

A2.3 1.14 = 1.4641 √2=1.41… よって (1.14)2 >(√2)2 よって 1.18 > 2

大小関係の証明がないと不等号の部分が正しいという根拠を失ってしまうわけですね。そのため証明が先に必要になります。証明の部分は今回の問題で必要となる範囲でのみ証明がされていればOKなので指数の部分が自然数のみとなっていたりしています。あとは問題の状態が満たされるように概算を行っていけばいいわけですね。このときに8が23ということをうまく使っていくのが美しいところでしょうか。なお根号に関する計算はテスト問題で処理する場合のために開平方で計算しているという仮定です。そのため有効桁は3桁が確定すれば次に進む、という手順で行います。

 

二項定理パターン

高校生レベルならこれを使って示してほしい、という意味の問題でした。解答はこちら。

A3. 二項定理を用いると

よってx=0.1,n=8を代入すると0以上8以下の整数kにおいてであり、

こちらの場合は数列の極限とかいろいろなことを考える前段階の証明として一度はやっておいた方がよいと思われるものです。似たような証明であればテスト問題や入試問題にも出るかもしれませんね。ということをわざわざ国立大学の前期日程の試験が終わった後で書かなくても…

 

数学を使って考えることができたでしょうか

今回は大きく分けて3パターン(間接的な方法ではさらに3つ)で示してみましたがほかに考えついた人はこの記事のコメントにでも返していただけるとありがたいです。なお、二項定理パターンはほかにも理科系(主に物理)科目の計算で1より微妙に大きい数や小さい数を近似するときに使うパターンでもあるので知っておいて損はありません。

…で、こういう問題を考えていると思うことは直接計算しなくても示すことができる問題というのはいろいろとある、ということです。現実世界でも直接答えを示せなくても間接的に示したりする例もあることですので知っておくとよいことがあるかもしれませんね。

 

Windows10でSage(SageMath)を使う (Bash on Ubuntu on Windows編)

いろいろと試していた結果やっと環境が固まってうまく動くようになったのでその記録として記事を書いてみたいと思います。以降の自分もいろいろな用途でSageを使うことになると思いますし、それ以外の人でこれを使って何かする人(後で解説)もかなり有用だと思います。

 

Sage(SageMath)とは

公式サイトを読んで見るなりWikipediaを調べるなりすればよいと思いますが数学の幅広い処理を扱うソフトウェアで計算機代数などを使用することができます。今現在の主な用途としては数値計算や計算機代数など計算機を使う数学において研究目的で使用されます。この場合ですと数学系の課題研究で担当の教授から紹介されたり代数学の論文でこのような計算方法で行います、という場合にSageのコマンドで紹介されていることがあり以降自分の研究を進めていく上で必要となることが多いようです。

もう一つ面白い使い方としては線形代数や数式処理も行うことができるため高校レベルまでのちょっと複雑な数式について数学の先生が答えから逆算して問題を作成したり、テスト問題を考えたときに解答が正しいかどうかをチェックしたり…という用途に使用できるのではないかと考えています。逆に考えると高校生が横着して数学の宿題についてSageで出した解答をそのまま持って行く、なんてことも考えそうな気もしています。高校生が使うのであれば途中式を書いて計算はしてみたけれど答えを提出する前に確認したい、という用途では使ってよいのでは?と考えていますがどうなのでしょうね。

なお、現在の正式な名称はSageMathと呼ぶようです。インストールするパッケージもsagemathという名前で書かれているようですので気をつけていきましょう。

 

Bash on Ubuntu on Windowsの環境を整備する

Windows10において2016年8月に公開されたAnniversary Updateですが、これの大きな更新の一つとしてBashをWindows環境で利用できるようになった、というものがあります。BashはLinux環境における代表的なシェル(この場合はOSとユーザーをつなぐ役割ととればよい)で、これのおかげで一部のLinuxのプログラムを余計な変換なしにWindows上で扱うことができるようになりました。昔からLinuxとWindowsを併用してきたユーザーから見ればかなりうれしい更新です。今回はこれを使うことにします。

Bash on Ubuntu on Windowsの環境を整備するのはいろいろなサイトで紹介されているので詳しい点はそちらに譲るとして簡単に説明すると作業は以下になります。

  1. 画面左下にあるWindowsのロゴを右クリックしてメニューより[コントロールパネル]を選択。[プログラム]=>[Windowsの機能の有効化または無効化]より[Windows Subsystem for Linux (Beta)]にチェックをして有効化する。(更新により再起動が必要になることもあり)
  2. 設定の[更新とセキュリティ]から[開発者向け]を選択してアプリの受け入れに関して[開発者モード]を選択する。
  3. 画面左下にあるWindowsのロゴを右クリックしてメニューより[コマンドプロンプト]を選択。プロンプト上で
     > bash 

    (先頭の>はプロンプト状態を表すもので実際には入力しない)と入力する。以下開発者のみの機能であることに同意した後Bash上のユーザー名、パスワードを入力して環境構築が行われる。

インストールにはしばらく時間がかかりますのでのんびり待ちましょう。環境の構築が完了するとスタートメニューにBash on Ubuntu on Windowsのショートカットが作成され、そのショートカットで起動すると上記のユーザーでログインした環境から処理が始まる、という状態になります。

ちなみにBash on Ubuntu on WindowsのインストールによってBash上で動くプログラムをgccなどのコンパイラによって作成することもできるのでC言語での簡単なプログラムも作ることができます。こういう目的で環境を構築するのもありかもしれません。

ただし、Bash on Ubuntu on Windowsの環境はWindows本体とは異なり自動では更新されません。そのため環境を構築していろいろなことをやるのであれば定期的にアップデートを確認して環境を更新していく必要が出てきます。環境の更新はインターネットへの接続が確保できている状態で

 $ sudo apt-get update 

というコマンド($はターミナル状態を示すもので実際には入力しない)で行います。また、この環境内ではマシン名の名前解決ということでsudoを使う場合などで変な警告を表示されることがあるので/etc/hostsに自分のマシン名(起動直後の表示では[(ユーザー名)@(マシン名):~$]となっているのでそれを目安に)をviなどで先頭行の127.0.0.1の後ろに書き加えてしまいましょう。

以降はBash on Ubuntu on Windowsを起動した場合はその窓のターミナルはUbuntuのコマンドラインだと思って作業することがある程度可能です。すべてのソフトウェアがあるわけではないのでapt-getで取得できないものはコンパイルがうまくできればなんとかなるかも、というレベルです。そのあたりは自己責任で。

 

XmingでGUIウィンドウが使えるようにする

SageMath本体には直接影響はしないのですがこれが使えるとグラフなどを見せるときに非常に楽になります。特にSageのコマンドライン上から描画命令を発行したときにXmingが正常に動いていればxdg-openコマンドを経由して(内部の関連付けにもよりますが)ImageMagickが呼び出されて最終的にXmingにより画面上にウィンドウが表示されます。これがないとSageからの画像表示を行いたい場合に一度ファイルへ出力した後それをWindows領域から見やすい場所にコピーして画像ビューワを使う、という手順となりかなり面倒になります。ちなみにこれを入れておけばgnuplotも表示できるのでその意味でも数学の授業で扱うことを考えたり…ということもあります。

 

インストールの手順としてはBash on Ubuntu on Windows + XmingによるGUI – Qiitaが詳しいのでそちらを見てもらえばよいですが、簡単に手順を書くと

  1. 公式サイトよりXming-6-9-0-31-setup.exeとXming-fonts-7-7-0-10-setup.exe(記事を書いている時点)をダウンロードしインストール
  2. Xmingを起動する。以下一度シャットダウン処理やXmingを終了させてしまった場合は表示させる処理の前にXmingを起動させること。
  3. 環境変数DISPLAYにXmingのサーバー値を設定する。通常は0.0なので
     $ export DISPLAY=localhost:0.0 

    というコマンドを実行する。必要であれば.bashrcの終端にこの命令を記述しておくと状態が登録されるので楽になる。なお、.bashrcに登録されている場合はウィンドウを開いた後でXmingを起動させてもうまく表示されることがある。サーバー値が間違っていれば失敗するのでそこには注意すること。

となります。ちなみに参考にしたページではxeyesを使ったチェックをやっていますがこちらの場合はこの後SageMathをインストールしてチェックするのでそのタイミングでやってもよいと思います。(うまく表示されない場合の切り分けのために先にテストしてもよい)また、LXDEとVNCを併用してGUI環境を作り出す方法もありますが今回そこまでする必要はないと思いますのでこういう方法を使っていきます。

 

SageMathをインストール

SageMathの場合は本体がPythonで記述されているため今回の場合はほとんどの機能をインストールすることができます。ただ、Ubuntuの公式サイトからパッケージを取得する方法ですとうまくいかない場合があるのでリポジトリから作業を行います。こちらは以下のコマンドを実行することでインストールすることができます。

$ sudo apt-add-repository ppa:aims/sagemath
$ sudo apt-get update
$ sudo apt-get install sagemath-upstream-binary

注意点としては容量がかなり大きい(5GB前後ある)のでWindowsの本体ドライブにそれだけの空き容量が必要であること、またかなりのサイズのデータをダウンロードするため時間がかかることです。数時間くらいかかることもありますので気長に待ちましょう。

 

SageMathの初期環境を構築する

インストールが完了すればSageMathを起動させて初期環境を構築します。といっても一度目の起動の場合は勝手に環境を構築してくれるのでそれを待つだけです。つまり、

$ sage

と入力すればOKです。なお、完全なLinux上で動作している訳ではないためSageMathを起動させるたびにRuntimeWarningが出てしまいますがそれは無視しても問題ないと思います。

 

SageMathの画像表示チェック

最後に画像が表示されるかどうかを確認して完了です。適当にグラフをplotしてみればよいわけですが、わかりやすくcircle命令を使います。例えば

 sage> circle((0,0),1)

としてグラフとして中心(0,0)、半径1の円が描かれたグラフが表示されるかどうかを確認します。デフォルトであればおそらくImageMagickが起動してXming経由で画像ファイルを表示します。コマンド実行後しばらくたっても画像が表示されないときはターミナル(SageおよびBash)をいったん終了させて再度起動させてみてください。それでもうまくいかないときはWindows本体を再起動させてXmingを起動させた上でSageMathを起動させて確認してみてください。ここまでやってうまくいかないときはXmingの表示テストにより単体で動作することを確認する必要があると思います。もしかするとeogをインストールしておく必要があるかもしれませんが…。

 

SageMathで数学Ⅰや数学Ⅱにありそうな問題を解いてみる

ここからは遊びです。例えば代数学の問題(数と式など)をやってみます。

Q1. を因数分解せよ。

A1. SageMathで以下のように入力して答えを得る。

sage> a,b,c=var('a b c')
sage> y=a*(b^2+c^2)+b*(c^2+a^2)+c*(a^2+b^2)+2*a*b*c
sage> factor(y)
(a + b)*(a + c)*(b + c)

よって解答は(ちょっと並び替えを行うと)

Q2. を計算せよ。

A2. SageMathで以下のように入力して答えを得る。

sage> y=sqrt(3)/(sqrt(3)-sqrt(2))-sqrt(3)/(sqrt(3)+sqrt(2))
sage> y.simplify_full()
2*sqrt(3)*sqrt(2)

よって解答は(根号の数を整理して)

Q3. 方程式を解け。

A3. SageMathで以下のように入力して答えを得る。

sage> y=x^4+x^3+2^x-4
sage> solve(y,x)
[x == 1, x == -2, x == -I*sqrt(2), x == I*sqrt(2)]

よって解答は(iを虚数単位として)

見事に途中式を無視して解答だけ出してしまったパターンとなってしまいました。これで数学の宿題として先生に提出したらほぼ確実にやり直しですね…。なお、記事を書いているときに書いている当の本人が本当にこんなことができるのだ、と妙な感動を起こして笑ってしまったのはおいておきましょう。

上記では問題を解く方向でやりましたが問題を構築するとき(例えば因数で表された状態の式を展開して問題にする)もexpandなどでかなりうまくできます。なお、根号の状態など一部の処理は(A2のように)必ずしも簡単になるとは限りませんので解答が出た後で整理するなどが必要だったりそもそもその式をうまく表現できない場合がありますのでそこまで期待しない方がよいでしょう。もちろん研究にSageMathを使う場合は普通に必要な処理を使っていってください。

 

1/0を数学的、教育学的、プログラム的に考える

というわけで今回は三種すべてに絡んだネタをやっていきたいと思います。この頃いろいろな場所でこの「ゼロ除算」の話が書いてあったのでそれがあり得る環境としてこの3つで書いていきたいと思います。というかゼロ除算で問題になるのは大別するとこの3つになるような気がしないでもありません。

 

数学的にはどのように扱うか、をおさらいする

まずこれが大切です。ここの認識が誤るとその後ろの2つについて「なぜそういうことになるのか?」を説明できなくなる可能性が高いからです。注意していきましょう。

まず数学的に1/0を考える場合、この演算を代数学を主としてとらえるか解析学を主としてとらえるか、によってかなり差が出ます。基本的には代数学の考え方が主となるのですが…。

 

代数学の考え方で1/0を考える

代数学で1/0を考えるときはたいていの場合『「1」や「0」は整数と考えてその中に自然に定義される(乗法の逆演算である)除法を用いて演算せよ』という問題と考えることができます。ここで問題となるのが「整数」や「乗法」および「逆演算」をどう考えるか、にあります。そもそも代数学では0や1は実は形式的な記号と考えることができます。また、今回の場合「整数」を対象としたとしてその場合乗法だけではなく加法も同時に定まっていると考えるとこの演算は「整数環、あるいは有理数体(実数体、複素数体)上で」という制約がさらに考えられる、というところまで考えないと正しく考えることができません。

で、ここまで来て初めて公理系から考えていきます。必要となるのは環の公理および体の公理です。まずは環の公理から。Wikipediaにある環の公理とは少し違いますが私の持っている教科書の書き方に準拠します。

加法と乗法という2つの演算が定義された集合Rが環(ring)であるとは次の4つの条件を満たすことである。(この4つを「環の公理系」と呼ぶ)

  1. Rは加法に関して加群である。
  2. Rは乗法において結合法則を満たす。
  3. Rは乗法と加法において分配法則を満たす。
  4. Rは加法の単位元0Rとは異なる元1Rが存在しに対してを満たす。

ちなみにこの公理から証明される定理として

加法の単位元0Rに対してとなる

があります。次に体の公理です。

環Rにおいて以下の条件を満たすときRは体(field)であるという。

  1. Rは加法の単位元0Rを除いて乗法において逆元を持つ。
  2. Rは乗法において交換法則を満たす。

で、ここまで見てみると気がつくと思いますが「0の逆元は体の公理系では定義されていない」ということです。わざわざ体の公理でも「0Rを除いて」ということになっています。このことから代数学的には体において「1/0」という操作は定義されていない(考えない)ということになっています。また環で考えたとしても除法は乗法の逆演算として考えるのでこの場合は考えることができない代物になっています。演算ができないというよりは考えない、が正しいです。ちなみに上記からわかると思いますが0/0も代数学の環や体では定義されません。

 

解析学的の考え方で1/0を考える

で、これで終わらないのが数学です。代数学的にはそうなのですが、解析学的には極限の考え方を用いることでいくつかの場合によって値を考える、ということを行います。つまり直接的に1/0は定義されていないとしても0にごく近い範囲で考えれば除数は0ではない限り乗法において逆元を持つ(有理数体や実数体より)ので0に近づけていくとどうなるのか?というものです。

たとえば関数を考えてxを1から0に正の数として近づけて答えを考えます。すると

  • 1/1=1
  • 1/0.1=10
  • 1/0.01=100
  • 1/0.001=1000

のように答えが大きくなっていっているのがわかります。これを続けていくなら1を一つ前に考えていた数より0に近い正の数で除法を行うと一つ前の答えより正の数として絶対値が大きな値となりどこかで一定の答えとなることはないという結論が得られます。で、これを極限の書き方で書くととなるわけです。なお、この無限大(∞)という書き方ですがこれは数ではなく状態を表す記号です。そのため数としての演算は一切できません。

ただ注意が必要なのが今は「正の数として」近づけていきましたが逆に「負の数として」近づけてみるとどうなるでしょうか。xを-1から0に負の数として近づけて答えを考えると

  • 1/(-1)=-1
  • 1/(-0.1)=-10
  • 1/(-0.01)=-100
  • 1/(-0.001)=-1000

ということで想像できると思いますがこの場合は1を一つ前に考えた数より0に近い負の数で除法を行うと一つ前の答えより負の数として絶対値が大きな値となる、という結論が得られます。上と同様に極限の書き方で書くととなります。

関数の場合は実は近づけ方によってx=0の極限を考えると複数の答えが出てきてしまします。そのため、解析学的にも極限を考えたとしてもx=0における極限は存在しない、という解答となります。(ただし正の方向から近づけた場合は正の無限大、負の方向から近づけた場合は負の無限大という解答にはなります)

おまけですが、解析学的として0/0を考えるといろいろと大変なことが起こります。たとえば関数を考えるとx=0では0/0の形となり値を持たない、となりますが極限を考えれるととなりnの値に依存した答えとなります。これだけ見てもわかりますが0/0を見ただけでは極限値がどうなるか解析学的にもわからないわけです。

 

教育学的にはどう扱うべきなのか考察する

問題なのはここですよね…。このセクションについては完全に個人的見解となりますのであしからず。

まず、学習指導要領および学習指導要領解説にゼロ除算について何か書いていないかな~?と思って読み解いてみたのですがさすがにその部分は疑問に持つ児童や生徒はいたとしても学習する項目としてではないので言及は一切ありませんでした。このことからもし児童や生徒に質問された場合どう返すか、は先生の考え方および力量に依存することになると考えられます。

次に除法を学習するときにどうやって学習するか、からゼロ除算について何かいい言い方がないのか?を考えてみました。気になったのが小学校三年生での除法と乗法、減法との関係についてで、12÷3の意味を考える場合に、

包含除は3×□=12の□を求める場合であり、等分除は□×3=12の□を求める場合である。また、実際に分ける場合でも、包含除も等分除と同じ仕方で分けることができることなどにも着目できるようにしていくことが大切である。

とあるので、ゼロ除算を除法について習ったばっかりなら「じゃあ1÷0の答えを考えてみるけれども0×□=1となる□に当てはまる数はある?ないよね?だから0でわることはできないんだよ」というよくある教えかたがこの場合は適しているといえそうだ、と考えました。また減法との関連であまりが出る除法においてもカードを分ける場合などの例を使うことから「カードを配るやり方で1÷0を考えてみるけれども、一枚のカードを一人に一枚も配らないで配ったふりだけをすると何回できる?(なんか不思議に思えるけれども)何回でもできるよね。そうすると答えが出そうにないね」という言い方になるのでは?と考えました。

ちなみにこの考え方ですが、前者の言い方は数学的には代数学における「0の逆元は定義されていない」を形式的に説明したものであり、後者はどちらかというと解析学における正の数から0に近づけていったときの極限の考え方に近い説明だと考えています。

なお、この後文字と式で文字を使った式を学んだり、方程式で式の変形を考え始めるといつの間にかゼロ除算をしてしまったパターンが現れてくることもあり、そのときは「ゼロ除算となる場合を分けて考えないと正しくない答えが入ってしまうね。これはゼロで割る、ということができない(定義されていない)からこうなるのだよ」という説明はできそうな気がします。高校レベルでも極限までいければだいぶ説明がしやすいですが…。

 

最後にプログラム的にはどうなる?

実はいろいろなコメントを読んでいて一番気になったのがこのポイント。「1/0はDivision by zeroでエラーとなる」という発言が多かったです。ただし注意してほしいのが(たいていの人は理解して言っていると思いますが)対象のプログラミング言語や変数の型によっては必ずしもそうではない、ということを書いておきたいと思います。

以下のC言語のサンプルコードはすべてゼロ除算をしているパターンです。

#include <stdio.h>

int main(void)
{
        printf("1.0/0.0=%f\n",1.0/0.0);
        printf("1.0/(-0.0)=%f\n",1.0/(-0.0));
        printf("0.0/0.0=%f\n",0.0/0.0);
        printf("1/0=%d\n",1/0);
        return 0;
}

これをgccでコンパイルしてみました。ファイル名をtest.cとしてやってみると

$ gcc test.c
test.c: 関数 ‘main’ 内:
test.c:8:21: 警告: ゼロ除算が発生しました [-Wdiv-by-zero]
  printf("1/0=%d\n",1/0);

となります。警告が出ているのは実は一番最後の1/0だけで残りの1/0や0/0は警告が出ていません。さらにできたファイルを実行してみます。

$ ./a.out
1.0/0.0=inf
1.0/(-0.0)=-inf
0.0/0.0=-nan
Floating point exception (コアダンプ)

例外により強制終了しているのは最後の演算だけで、残りの3つに関しては(一応)答えを出しています。これはどういうことかというと浮動小数型の場合はIEEE754にもありますが無限大やNaN(Not a Number、非数)が定義されていて、浮動小数として演算を行った場合はそれぞれ解析学的に極限を考えたものとして計算する、という動作になります。0/0の場合は極限が不定となるためにその状態として非数を用いて表現されているのがわかります。浮動小数型の場合は科学技術演算や3D演算等で無限大を考える必要があるのでこの方が都合がよいのでしょう。また整数型の場合は代数学的に計算されると考えればよいようで、そうなるとゼロ除算の結果は定義されていないため直接わかる場合はコンパイラによる警告が表示され、実行時では例外となるわけです。

 

ちなみにスクリプト言語としてPHPでやってみるとどうなるか、というとこういうコードで試してみました。

<php
  print 1/0;
?>

これをtest.phpに保存して実行してみると

$ php test.php
PHP Warning:  Division by zero in /…/test.php on line 2
INF

ということでゼロ除算による実行警告は出てきましたが計算結果としてはINF、つまり正の無限大となったわけです。なのでこの処理をただの警告と処理するなら常に「エラーとなる」訳ではなく、処理をそのまま継続することが可能です。このあたりは注意して扱う必要があります。

 

本当に考えるのであれば数学上での考え方を基礎にして考える必要があり

高校以下の数学および算数やプログラムでもそうですが、元となる数学の考え方をそれぞれに落とし込んだものですので元の考え方を知らないと理由を突き止めることは難しくなります。もちろん結果そうなるだけで納得できるならそれはそれでもいいですが、深く知っておくと似たような場面で理由が連想できるようになり、人に説明するときにうまく説明できるようになったり自分で問題が起こったときに学ぶことができるようになると思います。