アジマティクス

ここをこうするとおもしろい

それじゃあ任意の自然数をひっくり返す関数でも作って遊ぶか

f:id:motcho:20170117064709p:plain

関数を作るのって、結構楽しいんですよね。作曲や絵を描くのと同じで創作意欲が満たされるというか。

何言ってるかわからないと思うので、実際に関数を作って遊んでるときの私の脳内をトレースしました。

関数を作る

あ〜〜〜ヒマだな。関数でも作って遊ぶか。

そうだな......。例えば「1234」を「4321」にするみたいな、「自然数をひっくり返す関数」とかどうかな。

273なら372557188なら881755。うんうん。できなくはなさそう。ググってみたけど有名な関数でそういう機能を持つものはないみたいだな。いいぞ。作りがいがある。

関数だしとりあえずf(n)とでも名前つけとくか。こんな感じの問題になるかな。

自然数nに対して、nの各桁の値の並びを逆順にした数を与えるような関数f(n)を作れ。

うん。ワクワクしてきたぞ。なんでだろうな。絶妙に自分にも作れそうなレベルだからかな。

基本的な方針

a千b百c十d(エーせんビーひゃくシーじゅうディー)みたいな自然数って、数式で書くと

1000a+100b+10c+d

って表されるから、これを逆の

1000d+100c+10b+a

に変換してくれるような関数を作ればいいわけだよな。そうなると......。まずは自然数nの○桁目の数を取り出す関数」を作って、それから並べ替える、という方針を取るとよさそうかな。

こいつらが使えそうだ。

武器1

\operatorname{mod}\left(n,10^k\right):モッド。順番通りに「モッドエヌのじゅうのケーじょう」と読む。n\operatorname{mod}10^kと書いても同じ意味。自然数nkを与えてくれる頼もしいやつ。n256k2なら、256の下2桁ということなので\operatorname{mod}\left(256,10^2\right)=56n=890625k=4なら625
※実際には、n10^kで割ったあまりを計算している。

武器2

\operatorname{floor}\left(n\right):フロア。「フロアエヌ」と読む。\lfloor n \rfloorとも書く。n整数部分を与えてくれる心強いやつ。\operatorname{floor}\left(6.28\right)なら6\operatorname{floor}\left(9.80665\right)だと9。四捨五入ではなく、小数点以下をバッサリ切り捨てる。モッドとは血が繋がっている。

まずはどうするか

とりあえず適当なnを選んでひっくり返すことを考えよう。1234とかでいいかな。いやマズいな。ひっくり返したときに「1桁目である1」「2桁目である2」とかになっちゃってややこしいからな。......6174あたりにしよう。

まずは1桁目を取り出すことを考えると、これはmodにかけるだけですむはず。「1桁目」なので10^1をカッコに突っ込んで、

\operatorname{mod}\left(6174,10^1\right)

でいい。計算するとたしかに4だ。1桁目が取り出せている。

では2桁目は? 6174からその2桁目たる7を取り出すには?

これは「下2桁を取り出して」「\frac{1}{10}して」「整数部分を取り出す」とすればできそうだ。

まず下2桁を取り出すためにmodにかけて74

\operatorname{mod}\left(6174,10^2\right)=74

それを\frac{1}{10}して7.4

\displaystyle \frac{\operatorname{mod}\left(6174,10^2\right)}{10}=7.4

最後にその整数部分をfloorで取り出して7だ。

\operatorname{floor}\left(\frac{\operatorname{mod}\left(6174,10^2\right)}{10}\right)=7

できたできた。ちゃんと取り出せている。

じゃあ3桁目以降も全く同じ考え方でいけるはずだ。6174の3桁目たる1を取り出すには、まず下3桁を取り出す。

\operatorname{mod}\left(6174,10^3\right)=174

1がほしいので今度は\frac{1}{100}する。

\displaystyle \frac{\operatorname{mod}\left(6174,10^3\right)}{100}=1.74

最後に整数部分を取り出す。つまり小数点以下をバッサリ切り捨てる。

\operatorname{floor}\left(\frac{\operatorname{mod}\left(6174,10^3\right)}{100}\right)=1

よしよしできたできた。ギュッと押しだして、はみ出た部分をバッサリ切る。なんかトコロテン作ってるみたいな気分だな。トコロテン作ったことないけど。

\operatorname{mod}\left(6174,10^4\right)=6174   下k桁を取り出して、

\displaystyle \frac{\operatorname{mod}\left(6174,10^4\right)}{1000}=6.174   ギュッと(小数点以下に)押し出して、

\operatorname{floor}\left(\frac{\operatorname{mod}\left(6174,10^4\right)}{1000}\right)=6   はみ出た部分をバッサリ切る。

今度作ってみようかな。トコロテン。

問題発覚

1桁目を取り出したいとき、2桁目を取り出したいとき、3桁目を取り出したいとき......。ここまでで、何桁目だろうとそれぞれの式がわかったのだから、これはm桁目を取り出したいときの式に一般化できるよな。法則性から考えて、こうすればいいはず。

自然数nm桁目を取り出す式(関数):\displaystyle \operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^m\right)}{10^{m-1}}\right)

さっきまでの式と内容は同じはずなのに文字式になるとなんか急にわかりにくくなる感があるな。具体例って大事。

さて。そしたらあとはもうこれを並べ替えるだけだな。取り出した1桁目から順にa,b,c,dとしたらこれをひっくり返すには、1000a+100b+10c+ dって風に足していけばいいわけだから......。

あれ! ダメじゃん! これだと4桁の数にしか使えないじゃん!!

この方法で例えば57をひっくり返そうとすると、4桁の数0057だとみなされて7500になっちゃう。

あ、まあ別にダメではないのか。それはそれでそんな関数もアリだもんな。何か一つの答えがあるような問題を解いてるわけじゃないから、もうこのへんは好みの問題だな。個人的な好みとしてはやっぱり57をひっくり返したら75になってほしい。nが2桁のときは2桁分だけひっくり返す、4桁のときは4桁分だけひっくり返す。そういう設定が必要だ。ということは......。

nの桁数を求める関数も必要だなこれ。

桁数関数

「桁数 関数」でググっても、excelとかにおいて数字の文字列としての長さから桁数を求めるものばっかりヒットして、数学的な桁数関数ってものはなかなか出てこない。意外と有名なものはないんだな。じゃ作るしかない。

作るとなると、やっぱりあいつが必要になってくるだろうな。

武器3

\log _{10}\left(n\right):ログ。「ログじゅうのエヌ」と読む。「10を何乗するとnになるか?」という意味として捉えることができ、例えば\log _{10}\left(1000\right)だと「10を何乗すると1000になるか?」ということになるのでこの値は3となる。
かつて多くの船乗りの命を救った英雄。

\log _{10}\left(100\right)は「10100にするには何乗か?」と読める。これはもちろん2だ。\log _{10}\left(1000\right)だと3だ。

\log _{10}\left(1000\right)3ってことは、\log _{10}\left(999\right)だと3にはちょっとだけ満たないってことだから、2.999\dotsとかそれぐらいの値になるはず。

nが4桁である1000のとき\log _{10}\left(n\right)3で、3桁である999のとき2.999\dots。つまり、この整数部分をとって1を足せばnの桁数が出てくれるということでよさそうだ。こうなる。

nの桁数を取り出す式(関数):\operatorname{floor}\left(\log _{10}\left(n\right)\right)+1

ためしに1729を入れてみると、たしかに4になる。196882だと6。そうなるように作ったのだから当然だ。この桁数関数をd(n)とでも置いておこう。

まとめます

よしっじゃあ2つの関数をまとめるぞ!

最上位の桁の数から考えよう。nをひっくり返したf(n)の最上位にある数は、もとのnの下一桁、つまり関数 \operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^1\right)}{10^{1-1}}\right)で取り出される数だった。6174なら4。それを最上桁まで押し上げるには、10の冪をかければいい。元が4桁なら1000を、5桁なら10000を。m桁なら10^{m-1}を。6174は4桁の数なので10^{4-1}1000をかければいい。元の数nの桁数はd(n)で求められたので、10^{d(n)-1}となる。つまりこうだ。

\displaystyle 10^{d\left(n\right)-1}\operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^1\right)}{10^{1-1}}\right)

n=6174のとき、これがすなわち4000となる。次はここに700を足したい。下から2番目の数を上から2番目にしたいわけだ。

上から2番目の数は、下から2番目の数を取り出したものにこんどは10^{d(n)-2}をかければいい。

\displaystyle 10^{d\left(n\right)-2}\operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^2\right)}{10^{2-1}}\right)

これが700。さっきの4000と足して4700

次はこうだ。

\displaystyle 10^{d\left(n\right)-3}\operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^3\right)}{10^{3-1}}\right)

12と変化している部分を3にしただけ。これが10。一応n6174を入力して確かめてみるか。モッドは下k桁を与える関数だったから......。

\displaystyle 10^{d\left(6174\right)-3}\operatorname{floor}\left(\frac{\operatorname{mod}\left(6174,10^3\right)}{10^{3-1}}\right)

= \displaystyle 10^{4-3}\operatorname{floor}\left(\frac{174}{10^{2}}\right)

= \displaystyle 10^{1}\operatorname{floor}\left(\frac{174}{100}\right)

= \displaystyle 10\operatorname{floor}\left(1.74\right)

=10\cdot 1

=10

うむ。あってるな。

最後はこう。

\displaystyle 10^{d\left(n\right)-4}\operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^4\right)}{10^{4-1}}\right)

これらを1から4まで全部足し合わせればいいわけだ。4桁の数では1から4までだったわけだから、一般にd(n)桁だと1からd(n)まで足せばもう完成のはず! 総和記号を使って書くとこうなるかな。

\displaystyle\sum _{k=1}^{d\left(n\right)}10^{d\left(n\right)-k}\operatorname{floor}\left(\frac{\operatorname{mod}\left(n,10^k\right)}{10^{k-1}}\right)

できた! これが「任意の自然数をひっくり返す関数」だ!!!

完成

一応コンピューターさんにも正しいかどうか見てもらおう。

https://www.desmos.com/calculator/23dohpo6nd

(上のリンク内「n=」の部分に好きな数字を入れると真下の式のところに計算結果が表示されます)

関数! 496をひっくり返して!

f:id:motcho:20170117050050p:plain

関数! 33550336をひっくり返して!

f:id:motcho:20170117045943p:plain

よしよし。できてるできてる。えらいぞ! 関数!

これで完成だ。満足満足。おおむね満足だけど、欲を言えばもう少し簡潔な式になってほしかったかな。

自然数をひっくり返す」というだけなのにここまで複雑な式になってしまうのは、それはそれで興味深いけどもうちょっと使い勝手のいい式になってくれるといいんだけどな。そしたら例えば13^2=16931^2=961との関係性みたいな、ひっくり返す系の数学的事実に気軽に考察を与えることができるようになっていいと思うんだけど。まあいいや。今後の課題としよう。

さて

あ〜〜〜〜〜〜今日も今日とてヒマだな。ヒマなはずないんだけどな。やること大量にあるし。やることがいっぱいありすぎるとどれから手つけようウワアアってなっちゃって逆に何も手につかないんだよな。仕方ないし関数でも作って遊ぶか。

そうだな今度は例えば......。「任意の自然数を小数点以下で繰り返す関数」とかどうかな。

7なら0.77777777...1024なら0.102410241024...。お、いい感じかも。ちょっと簡単すぎるかな? いや、簡単だろと思ってやってたら思いもよらぬことが判明したなんてのはよくあることだしな。とりあえずやってみるか。何から考えたらいいだろ。まずはそうだな......。