前回からコンテンツを増やします.
※価格は記事執筆時のものです. 現在の価格はApp Storeから確認ください.
レビュー時のiOSバージョン : iOS15.2.1
スポンサーリンク
ダウンロード
実際に体験するのが早いでしょう.
前回投稿した開区間、閉区間に加えふたつの半開区間から選択できます.
その後入力した実数が選択した区間に含まれるかどうかを判定するレシピです.
画像の通りショートカットでの小数点以下の精度にも対応します(小数点以下の精度は16桁).
半開区間の判定も熟します.
前回
前回紹介したのは開区間と閉区間でした.
(そういえば閉区間としてならif文一つで済みましたね)
二次関数を使って代入した値の正負(または0)によって判定するというものです.
今回は半開区間について考えてみます.
端点と範囲外の扱い
半開区間の場合は前回のようにはいきません.
通常の指数関数を使う手もあるんですが、代入する値が大きくなると簡単にオーバーフローしたり小数点以下で丸められてしまうデメリットがあるため使えません.
今回は底を-1とする指数関数と二次関数を併用します.
ここでは左半開区間(a,b]で考えます.
画像のように、数直線上に点a,bがあるのをイメージします.
半開区間(a,b]のエリアは緑の範囲内ですが、端点に相当する境界線が問題になります.
理想は上の画像のようなグラフを作ることです.
このとき値が正である場合、その値は半開区間(a,b]に含まれることになります.
しかし、ショートカットの各種アクションの組み合わせではおそらく不可能です.
そこで段階を踏んでこれに似たようなものを作ります(実際には対して似ていませんが).
ようは以下の4点を満たす関数であればなんでも良いわけです
なる実数cについて、
- 上記を除く変数
について、
区間[a,b]における正負の判定が重要のため、上の条件4は緩いものとなります.
理想はすべて0とはじめに書きましたが、条件1~3を満たすためであれば負数でも問題ないわけです.
というわけでまずは画像のような周期関数を作ることを考えます(分離している箇所は黒で埋まっている点の方が値).
周期関数の代表例は三角関数ですが、度数法にしろ弧度法にしろ変数の扱いがややこしくなるため、今回は上で触れた指数関数を使います.
しかしこの関数は
でのグラフ化など、そのままでは厄介な存在です.
そこで指数xは、代わりに小数点以下一位を四捨五入したものに差し替えます.
ショートカットの「計算機」であれば
(-1)^(rint(入力))
、あるいはWolframAlphaであれば
(-1)^(Round(x))
になります.
しかしこれだとグラフを見てわかる通り、希望の状態から0.5だけズレています.
そこで入力(変数)を1/2だけ引いて全体を右に1/2ズラします.
これで原点での値が1、間隔1の方形周期関数が得られます.
しかしこれで終わりではありません.
これを好きな閉区間[a,b]上で1となるようにするため、更にパラメータを加えます.
この辺は説明すると蛇足気味になるので省略しますが、x=a~bで1、両側で-1となる方形周期関数は、今回の場合以下で得られます.
ショートカットの「計算機」アクションでは、Roundでなくrintになります.
またレシピでは範囲外を0にするためにここから1を足したものを使います.
上はa=-1、b=2の場合をWolframAlphaで計算したものです.
さて、このままでは区間[a,b]以外にも正の区間があるためまだ十分ではありません.
不要な区間を何らかの形で0以下にする必要があります.
そこで二次関数を使います.
具体的には、上の画像のような、
- 上に凸
- 頂点の
座標が
を満たす二次関数を使います.
これを満たす二次関数が例えば
であることは容易にわかります.
これと上で作った方形周期関数(に1を足したもの)をかけ合わせると画像のようになります.
見やすくすると画像のようになります.
これで目的は達成されます.
というわけで最後の関数は以下で表わせられます.
この式の変数に代入した値が正であればその値は区間(a,b]に含まれており、非負であれば含まれない…ということになります.
同様に、もうひとつの半開区間[a,b)の場合は以下となります.
指標となる値が計算できれば、後はif文で場合分けするだけです.
レシピ化
配布したレシピは開区間、閉区間を含む4種から選択し、入力した値がその区間に含まれるかどうかをシンプルに判定します.
前回同様、端点の値は「辞書」アクションを使います.
「メニューから選択」で4種の区間から選ばせます. 開区間、閉区間については省略します.
「入力を要求」で実数を入力させ、先程の関数に沿って「計算機」アクションで値を計算します.
結果が0より大きいならば、区間に含まれる旨のテキストを作り変数に代入します.
そうでない場合も同様に.
新たに「メニューから選択」を追加し、プロンプトに上で作ったテキスト(の変数)を入れ、やり直すか終了するかを選択させます.
結果を「結果を表示」で表示させて終わり、またレシピを実行しなおし…は面倒ですからね.
〆
これよりもシンプルで大小の値に対応できる関数はいくらでもあると思います.
現状ここで紹介したケースも、二次関数を使用している影響で大きな値に対してそれなりに小さな負数、つまり絶対値を取って大きくなるためやはりある程度大きな数になると限界が来ます.
その次善策としては前回も紹介したように、因数、
ごとに予めある程度の定数で割っておくことです.
アクション数が増えるデメリットもあるので目的によっては不要かもしれません.