もう一人のY君

iPhoneアプリのレビューやアップデートレビューなどを書いています. たまに数学の記事も書きます.

もう一人のY君 MENU  MENU

【iPhoneショートカット】ニ次方程式、三次方程式の、開区間の実数解の個数を求める【スツルムの定理】

f:id:thetheorier:20200426131818p:plain

 なかなかうまく行かず, 時間を見つけて悪戦苦闘して半年以上経ってしまいました.

 

ショートカット

ショートカット

  • Apple
  • 仕事効率化
  • 無料

※価格は記事執筆時のものです. 現在の価格はApp Storeから確認ください.

 レビュー時のバージョン : v4.0.1

 

スポンサーリンク

 

 

 

ショートカット

f:id:thetheorier:20200425161833p:plain

 今回はフローを紹介するのは諦めます.

 というのも画像の赤枠で囲まれた5つのショートカットの合算で, またアクションの数を見てわかる通りで全体が380ととても大きいためです.

 後で少し触れますが一つのショートカットで書こうとすると実際にはこの合計からさらに1.5倍以上必要となってしまいます.

 多くなった事情は以下で.

 

 というわけで今回はiCloudリンクだけ貼ることとします.

 数が数なのでURLもベタ貼りにしておきます.

 

[メイン] https://www.icloud.com/shortcuts/308fa52b91e9405b9b739e10ca99dfdb

…実際に使用する際はこのショートカットを起動します.

 下の4つはサブ関数なので単体では意味はありませんが5つすべてある状態ではじめて上記が使えますので忘れずに入れてください.

 

[deg(f)=3] https://www.icloud.com/shortcuts/c99b36c53b6547a0a9c7aea7ccd238e6

[V(x):deg(f)=3] https://www.icloud.com/shortcuts/e75665debf714e19b0a6097bdedee461

[deg(f)=2] https://www.icloud.com/shortcuts/cc361953632c4079a938c2a8c77d0895

[V(x):deg(f)=2] https://www.icloud.com/shortcuts/7715e7bcec474a3fa200a43cbca02dda

 

 

 以下は簡単な説明と解説になります.

 今回のショートカット作成の上で分かったショートカットのデメリットとその解決策(のようなもの)も書いておいたので余裕のある方は読んでみてください.

 

 

使い方

f:id:thetheorier:20200426094835p:plain

 まず開区間となる(a,b)の両端を指定します.

 その後3次関数か2次関数かを選びます(つまりこのショートカットでは2次3次方程式をサポートしています).

 

f:id:thetheorier:20200426095354p:plain

  あとは選択した3次関数,2次関数に応じて必要な分の係数, 定数項を入力すれば然るべき値を返してくれます.

(方程式をいい感じに表示することはできるんですが面倒なので括弧で誤魔化してます)

 

 


【iPhoneショートカット】スツルムの定理

 

 

どのくらいまでいける?

 過去に指摘した通り, 例えば整数値であればショートカットは19桁までをサポートしています.

 20桁以上でも可能ですがその場合千の位で四捨五入されてしまいます.

 小数の場合は小数以下16桁まで, 17桁以降は17桁目で四捨五入されます.

 よってより精度を求められる状況ではこれらの制限を受けます.

 

 今回のショートカットではよっぽどでない限りここまでの精度の範囲内ですから多分気にすることはないと思います.

 

 試しに3次関数f(x)=3x^3 - 0.0099x+6.0099による方程式を考えます.

 

f:id:thetheorier:20200426115029p:plain

  f(x)=3x^3 -9.0099x+6.0099の外形は画像の通りです.

 x=1が解であることは明らかですが, 外形からするにx=1に非常に近い場所にもう一つ解があるはずです(中央の白い点は極値点).

 画像の通り, 拡大すると1.0005と1.0015の間に, より拡大すると1.00109から1.00111の間にありそうです.

 

f:id:thetheorier:20200426120146p:plain

 では実際に開区間(1.00109,1.00111)と指定してスツルムの定理を適用してみるとちゃんと1を返してくれました.

 この程度の精度ならちゃんとやってくれるようです.

 

 

実数解の個数がわかる仕組み

 このショートカットでは, 方程式の実数解の個数を計算するために先日紹介したスツルムの定理というのを用いています.

 

blog.thetheorier.com

 仕組みはとても簡単なのですが, だからといって同じことをパソコンにやらせても簡単である保障はありません.

 今回はその一例とも言えます.

 

 スツルムの定理では多項式とそれによる最大公約数を計算し, かつそれらを多項式関数として実際に代入することで値を得る必要があります.

 具体的には対象の多項式f(x)とそれをxについて微分したf'(x)について, 下のように「余り」を取っていきます.

 

f:id:thetheorier:20200425172954p:plain

 ようはユークリッドの互除法を数でなく多項式で行い, 「f(x)とf'(x)の最大公約数」を求めるのが一つの目的です.

 こうして得られた関数f,f'およびr_nについて,

 

f_0(x) = f(x)
f_1(x)=f'(x)
f_2(x)=-r_0(x)
f_3(x)=-r_1(x)

 

と定義しなおしたとき, 列f_nをスツルム列と言います.

 指定した開区間(a,b)について,x=aおよびx=bをそれぞれに代入し, 得られた値の列より, 「符号が入れ替わった数」をそれぞれV(a)およびV(b)とします.

 但し0になる部分は飛ばして数えます.

 例えば値の列が-1,0,3,2,-9であった場合, 符号が入れ替わった数は2個ですね.

 

 このとき, V(a)-V(b)が求める実数解の個数となります, これがスツルムの定理の簡単な説明です.

 

ショートカットの弱点

 ショートカットは可能な範囲で「自分でアプリが作れる」ような存在なので, アイデアが湧き, かつそれを実現することが可能であれば色々なアプリが代用できてしまいます.

 とはいえ対象が限られていたり, フォームも限定されていますからそれらを前提にして作る必要があるため必ずしも良いことばかりではありません.

 

 今回のショートカットを作る上で障害となったもの, デメリットであったもののいくつかは次のようなものでした.

 

多項式計算に弱い

 ショートカットアプリの登場まもなくに指摘した通り, ショートカットアプリの代数演算はC言語のような高級言語のそれとは異なり, PICで用いられるような主に「ニーモニック+オペランド」といった構造を取ります.

 これより複雑な処理はできません, そのため例えば1+2+3という(人の目で見れば)簡単な計算でも, ショートカットでは例えばまず1+2を計算し, その結果と3を足す…といったことをせざるを得ません.

 結果複雑な演算を要求されると一気に計算量が増加します.

 

 

  多項式による最大公約数は言ってみれば「割り算の筆算」で済みます.

 しかしショートカットでは人がやれば簡単な筆算はおろか多項式関数の値を計算することすら大変です.

 とはいえ代入はまだマシな方です, 筆算は流石にC言語でも容易でないため, こればかりは係数を定数として予め計算し, そこから代入する手法を取らざるを得ません.

 

 具体的な数で, 手計算で行えば大したことではありません.

 しかしコンピュータはそこまで器用ではありませんから, 係数を定数としてこれらの列を予め与え, 計算させる必要があります.

 では今回のスツルムの定理に関わるスツルム列は実際どうなるのか.

 

f:id:thetheorier:20200425173914p:plain

 結果は画像の通りです(texで打ち込むと読み込みが遅いので画像にしました).

 結果的には筆算でもここまでやっているということですね.

 見ての通りf_2以降はf_1までの係数を定数と置くことで見た目が簡単(な方)になっています, f(x)の係数をそのまま使うともっと複雑になってしまいます.

 

 いづれにしろ, この計算を高級言語でもないショートカットにやらせるわけです.

 しかも定理の都合上これらを2回分計算します.

 

 「単純に計算すればよい」, 口で言うのは簡単なのにそれが簡単でないのがショートカットの悲しいところです.

 多項式計算をもっとエレガントに行うアイデアがあれば良いんですが今回は思いつきませんでした.

 

 

「マジック変数」の罠

f:id:thetheorier:20200425175216p:plain

 計算を無闇に増やす要因は上記だけではありません.

 例えば, こちらはa0,a1,c0,c1の4つの変数を用いて「a1c0-a0c1」を計算するフローです.

 C言語ならこれも1文で終わりですがショートカットでは5アクション必要です.

 しかもこの結果を更に別で使おうものなら更にもう1アクション必要です.

 多項計算が一発でできない不便さがここにも現れます.

 因みに実際のところ, 4つ目の「変数を設定」は実際には必要ありません, 最後の「計算」の時点でこれがアクションの入力となっているからです.

 ショートカットには「マジック変数」という特殊な変数が存在し, 本来直前の出力を自動的に入力とするところを, もっと手前の出力をその場所の入力とすることが可能です.

 じゃあこれを使えば良いのでは?と思うわけですがアクション, こと数関連ではコトは簡単でないようです(バグなのかも?).

 

f:id:thetheorier:20200426082845p:plain

  具体例を見てみます(ショートカットのタイトルは無視してください).

 画像のように, 「1+1」というアクションと「1+2」というアクションを「計算」アクションでマジック変数によって足し合わせるというシンプルなものです.

 想像通りなら結果は5になるはずですね.

 

f:id:thetheorier:20200426083034p:plain

  しかし結果は6になってしまいます.

 つまり最後の「計算」アクションにある「計算結果」はどちらも「1+2」の出力である3となってしまっているのです.

 このようにアクションによってはマジック変数が正しく働かないことが起こりえます.

 これを回避するためには「変数を設定」でいちいち何かしらの変数に置き, 最後の「計算」でそれを使うこと…というわけです.

 

 結果, 「2つの積の差」だけでもこれだけのアクションを要する結果となってしまいます.

 一つ一つのアクションはシンプルなので処理時間に大きな差はありませんが, 塵も積もればなんとやらです.

  先程のf_2などに至っては推して知るべしです.

 関数として別のショートカットに分けた理由は同じ操作を2度行うもの一つですが一番大きな理由はこれに他なりません.

 

 マジック変数は一見便利ですが, 思った通りに処理されているかどうか自信がない場合は一気に作らず区切りを見つけて「結果を表示」アクションなどを使って逐一チェックしましょう.

 

 

ショートカットがやりやすい手法に

 というわけで今回のスツルムの定理に関係なく, 主に数処理関係はこれらの不便さに対応しつつ配置せねばなりません.

 

 

他のショートカットを関数として使う

blog.thetheorier.com

  ショートカットを別の関数で呼び出すことで関数の代わりにする手法は先日紹介したとおりです.

 冗長になりやすい場合は関数としてひとまとめにし, メインで呼び出す…というのはプログラミングでも当たり前に行う手法です.

 ショートカットアプリではその際

 

  • 関数とするショートカットを呼び出す際の「出力」を適切に選ぶ
  • 関数ショートカット先頭で上記を「入力」として取り出す(自分はいつも「テキスト」アクションに「ショートカットの入力」を配置し, 入力に応じて変数に置きます)
  • メインのショートカットに戻る際の関数ショートカット最後の「出力」を適切に選ぶ(値などの変数なら「テキスト」で出力し直します)
  • 戻った際に関数ショートカットの出力をメインのショートカットの「入力」

, この4点注意する必要があります.

 

 

関数ショートカットでやり取りする変数が多い場合

 ショートカットアプリがリリースされて間も書くに書いた記事では, 「テキスト」アクションにコンマで区切った各種変数を関数ショートカットの入力として渡し, それを「テキストを分割」でバラバラにしてから改めて変数として置き, 使っていました.

 

f:id:thetheorier:20200426091856p:plain

  今回は先日やっと使い方を理解した「辞書」アクションを利用しました.

 関数ショートカットを呼び出す直前に辞書を置き, 「ショートカットを実行」の入力に当てます(画像左).

 関数ショートカット側では出力されたその辞書を一旦「テキスト」アクションに貼り付け, これを「入力から辞書を取得」で再び辞書とし, あとは「辞書の値を取得」アクションで次々に取り出し, その都度変数に置く…という方法です.

 カンマ区切りよりはよっぽどマシなやり方ですね, これなら後で変数を追加することも簡単です.

 関数ショートカットからメインに戻る際も, 渡したい値について同じように行えば良いわけですね(必要があればこれに関する別記事も書くかもしれません).

 

 仮に渡す値が1種類でも, この形をテンプレートとして使用するといいでしょう.

 

 

ショートカットがやりやすいようにスツルムの定理を改造

 ともかく, こうして得られたスツルム列(3次方程式の場合4個, 2次方程式の場合3個)に, 指定の開区間(a,b)の両端であるa,bを代入して値を計算します.

 なので計算量の違いこそあれ, 結局3次方程式の場合は4×2=8個, 2次方程式の場合は3×2=6個の多項式による値を計算する必要があります.

 それぞれ2つずつはa,bが異なるだけで同じ多項式関数を使いますから, フローが長いのも考慮して関数として分離するのが現実的である…というわけです.

 また下記の事情を踏まえ, 正負の値となったものは予めそれぞれ1および-1に変換します.

 

 その後代入した値の符号が入れ替わった数V(a),V(b)を計算します.

 これも「0の場合は無視する」という, 人間なら簡単にできることが地味に難しい処理を行うハメになります.

 今回は「変数を追加」で, スツルム列の値が0でない場合に一つの変数に放り込み, すべて0であった場合を想定してその後ろに0を4つ(3次方程式の場合), または3つ(2次方程式の場合)追加します.

 こうして得られた列は例えば元のスツルム列を用いて得た列(3次方程式と想定)が1,0,-1,1であった場合,1,-1,1,0,0,0,0となっていることになります.

 この例の場合, 符号が入れ替わった数は2回なのでV()は2ということになります.

 通常であれば目視で2個であると判断しますがこれをコンピュータなどで計算するにはどうすれば良いかと考えました...

 結果思いついたのは階差を取ってその値で判定することです.

 例えば上の例で階差を取ると,

1-(-1),-1-1,-1-0
⇒ 2,-2,-1

 となります(3次方程式と想定したので元の列は4個, よって階差列は3個で固定です).

 この階差列で2または-2となる数がまさに「符号が入れ替わった部分」というわけです.

 先程スツルム列の値を-1,0,1に均したのはこの計算をしやすくするためだったわけです, 具体的な値でなく「符号が入れ替わったかどうか」が重要ですから.

 したがって階差列を更に絶対値を取り, if文で「1より大きい場合」にV()(初期値0)を加算すれば求める値V(a)およびV(b)を得ることができます.

 

 あとはV(a)-V(b)を計算すれば晴れて実数解の個数がわかります.

 

 

 需要があるかどうかはわかりませんが, ネタがネタなので整式の除法を理解している段階であれば定理による計算自体は難しくありません.

 

 因みにこの定理を用いて例えば「x^2 +kx-1=0が実数解を持つような実定数kの範囲を求めよ」的な問題を解くこともできます(簡単にできるとは言いません).