もう一人のY君

主にiPhoneのショートカットアプリのレシピやTipsなどを書いています. たまに数学の記事も書きます.

もう一人のY君 MENU  MENU

【iPhoneショートカット】シフト演算アクションを使ったビット操作

f:id:thetheorier:20210906104206p:plain

 先日使えることが分かった論理演算を使って, 簡単なビットシフト操作を検証します.

 

 

ショートカット

ショートカット

  • Apple
  • 仕事効率化
  • 無料

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

 レビュー時のiOSバージョン : iOS14.7.1

 

 

スポンサーリンク

 


 

 

シフト演算について

 我々が普段使っている数の操作は10進数ですが今回は2進数です.

 例えば1234という数を右に1桁動かすと123となりますね(小数以下に下がったものはここでは無かったことにします).

 これを2進数で行うのがビットシフトです.

 

 当然シフトする方向は右と左の2通りあります.

 右シフトは上の通りですが左にシフトする場合, 追加された末尾は0を入れます.

 例えば101(2)(2進数であることを表すのに、末尾に(2)を書きます)を左に1つシフトする場合は1010(2)になります.

 

 因みにシフトした結果は元の数とどういう関係があるでしょうか.

 例えば10=1010(2)を右に1シフトすると101(2)であり, これは10進数の5です.

 つまり右シフトは元の数を2で割る操作と言えます.

 

 しかし厳密には異なります, 例えば9=1001(2)は2で割っても整数ではありません.

 これを1右へシフトすると100(2), これは4ですね.

 元の数が奇数である場合, 1右へシフトした結果は元の数を1引いて2で割った結果と同じになります.

 

 言い換えるならば, 右へ1シフトさせる操作は数を2で割った結果を更に小数点以下切り捨てたものです.

 

 対して左シフトは単純に元の数の2倍になります.

 

 但しプログラム言語のように, 対応する値に限界がある場合は単純ではありません.

 例えば4ビットmaxの型で10=1010(2)を左に1シフトするとします.

 単純に考えれば10100(2)になるわけですが今回は4桁までしか表現できません.

 なので4桁に収まるよう, それを越える桁は削除されます, つまり今回の場合0100(2)=100(2)=4となります.

 

 iPhoneを含む昨今のスマホは64ビットなので基本的に2^64=18446...5551616(20桁)という数がビット操作のキーとなります.

 

 

基本演算

f:id:thetheorier:20210906105951p:plain

 シフト演算を「計算式」アクションで使用するには, 画像のように

 

11>>2

 

などと, 対象の数とシフトさせたい数で>の記号2つを挟みます.

 2つの数はともに10進数で書き, また結果も10進数で返ってきます.

 今回の「11>>2」は「11=1011(2)を右に2シフトする」という意味になります.

 1011(2)を右に2つシフトすると10(2)ですから10進数の2, というわけで結果は正しいですね.

 

 

 これを踏まえて, 好きな数を好きな桁だけ右シフトさせた結果を計算してみます.

 

 

f:id:thetheorier:20210906111046p:plain

  まず元となる数(numとしました)の入力をします.

 

 

f:id:thetheorier:20210906111144p:plain

 続いてシフトさせたい桁数(shift)と入力させ, 「計算式」アクションで

 

num>>shift

 

として結果を表示させます.

 

 

f:id:thetheorier:20210906111301p:plain

 結果を確認してみます.

 

 例えば11=1011(2)と3回右へシフトさせると

 

1011(2)→101(2)→10(2)→1(2)

 

なので1になりますね.

 

 

応用:指定桁のバイナリ表示

 今度は対象の10進数をバイナリ, つまり2進数にした値も計算し, それを入力フォームのプロンプトに表示した上で指定の桁だけ取り出してみます.

 

 10進数を2進数に変換するオーソドックスな方法は2で割り続けてその時々の余りを見ることですが, 今回はせっかくなのでこの変換もビットシフトで行います.

 

 

f:id:thetheorier:20210906111757p:plain

 まず前回同様, 元の数numを入力させます.

 numの(2進数での)桁数で繰り返しをするので2を底とする対数を取り, ceilで小数点以下を丸めます.

 但し単純に \displaystyle \text{ceil}\left( \frac{\log{\text{num}}}{\log{2}} \right) としてしまうとnumが2の累乗のとき「桁数」が1減ってしまいます, そこで \displaystyle \text{ceil}\left( \frac{\log{\left( \text{num}+1 \right)}}{\log{2}} \right) と, 分子側の対数の中をnumでなくnum+1とします.

 こうして得た値をnumの桁数としてdigitsの名で代入します.

 

 

f:id:thetheorier:20210906112759p:plain

 上で桁数が分かったのでこれを使って繰り返し操作を行います.

 論理演算の一つである論理積andはともに1である場合のみ1を返します.

 なのでチェックしたい桁を1の位までビットシフトし, 1と論理積をとればその桁が1か0かがわかるというわけです.

 例えば11=1011(2)の3ビット目は0ですが, これを右に2シフトさせると10(2), この結果と1の論理積を取ると0となります.

 この操作をきちんと書くと

 

(11>>2)and1

 

となります.

 この考え方を使えば好きな桁のビットがなんであるか…がわかるわけです.

 今回の場合は

 

(num>>tmp)and1

 

であり, この結果を順番につなぎ合わせれば対象の数numの2進表示が得られます.

 

 

f:id:thetheorier:20210906113910p:plain

 あとはこれを「入力を要求」のプロンプトなどに使いつつ, 先ほどと同じビットシフトを行った結果を計算, 表示させます.

 

 

f:id:thetheorier:20210906114036p:plain

 これで対象の数とそのバイナリ, ついでにその桁数がわかる状態で桁を指定できるようになりました.

 

 

f:id:thetheorier:20210906114958p:plain

 因みにはじめに指定する10進数の限界は16桁のようで, それを越えると下の桁が0に丸められてしまいます.

 

 

応用:NOT演算

 執筆時点でショートカットにはNOT演算はありません.

 ただ0と1を反転させるだけじゃ…と思うんですが無い以上は諦めるか, 他の手段を使うしかありません.

 

 

f:id:thetheorier:20210906115331p:plain

 というわけで考えられるもっともシンプルな代替案は

 

-1xor数

 

です.

 ショートカットではいわゆる「符号付き整数型」を使っているようですが, 表記上は-1で問題ないわけです.

 今回は試験的に0から10に対してnotの代わりにこの操作を行った結果を見ていきます.

 

 

f:id:thetheorier:20210906120812p:plain

 結果がこちらです.

 整数型が64ビットであること, そして2^64-1で反転していることもわかります.

 

 

f:id:thetheorier:20210906121543p:plain

 もちろん, -1と等価な2^64-1に置き換えても結果は同じです.

 

 

 次回はこのシフト演算を使った実用レシピを紹介します.