2016年3月12日土曜日

\(\mathrm\TeX\)マクロ 累乗、階乗、素数判定関数

剰余演算子のついでによくプログラミングで聞かれる数学的関数を幾つか実装してみた。

まず累乗

  1. \def\powercalc#1#2{
  2.         \newcount\t \t=#1 \relax%
  3.         \newcount\step \step=1 \relax%
  4.         \loop%
  5.                 \multiply\t#1 \relax%
  6.                 \increment\step \relax%
  7.         \ifnum \step<\q \repeat%
  8.         #1=\t \relax%
  9. }
t=#1を#2回掛けるだけの簡単なお仕事。(これじゃ指数部が負や小数の時は対応できないって?そもそもカウンタは整数値しか扱えないからいいのだ。)
\loopの扱いなどについてはキヨシ関数の記事を参照。
ちなみに#○は引数。

次が階乗。


  1. \def\function#1{
  2.         \newcount\t \t=1 \relax%
  3.         \newcount\step \step=1 \relax%
  4.         \loop%
  5.                 \multiply\t\step \relax%
  6.                 \increment\step \relax%
  7.         \ifnum\step<#1 \repeat%
  8.         #1=\t \relax%
  9. }

1から#1まで掛けるだけの簡単なお仕事。累乗とあんまり変わらない。

最後が素数判定。


  1. \def\ifprime#1{ %素数なら0,合成数なら1をjudgeに格納
  2.         \ifnum #1<2 %
  3.                 %1
  4.         \else%
  5.                 \newcount\judge \judge=0 \relax%
  6.                 \newcount\step \step=2 \relax%
  7.                 \newcount\max \max=#1 \decrement\max \relax%
  8.                 \loop%
  9.                         \newcount\temp \temp=#1 \relax%
  10.                         \surplus\temp\step \relax%
  11.                         \ifnum \temp<1 \judge=1 \fi%
  12.                         \increment\step \relax%
  13.                 \ifnum \step<\max \repeat%
  14.                 %\the\judge
  15.         \fi%
  16. }

本当はtrueとかfalseとかを返せるようにしたかったのだが引数のカウンタに上書きする以外の戻り値の返し方がわかんなかったので仕方なく素数なら0,合成数なら1をjudgeに格納することにした。
Java風に言うとvoidにしてグローバル変数に格納して返す、みたいな?(適当)
3行目と14行目をコメントから外せばdviに0か1を書き出すようになる。

さて、実行。


  1. \documentclass{article}

  2. \def\surplus#1#2{%
  3.         \newcount\n \newcount\m \newcount\t%
  4.         \n=#1 \m=#2 \t=\n \relax%
  5.         \divide \n by \m%
  6.         \multiply \n by \m%
  7.         \advance \t by -\n%
  8.         #1=\t\relax%
  9. }
  10. \def\minus#1#2{   \advance #1 by -#2 \relax}
  11. \def\increment#1{ \advance #1 by 1 \relax}
  12. \def\decrement#1{ \advance #1 by -1 \relax}

  13. \def\powercalc#1#2{
  14.         \newcount\t \t=#1 \relax%
  15.         \newcount\step \step=1 \relax%
  16.         \loop%
  17.                 \multiply\t#1 \relax%
  18.                 \increment\step \relax%
  19.         \ifnum \step<\q \repeat%
  20.         #1=\t \relax%
  21. }
  22. \def\function#1{
  23.         \newcount\t \t=1 \relax%
  24.         \newcount\step \step=1 \relax%
  25.         \loop%
  26.                 \multiply\t\step \relax%
  27.                 \increment\step \relax%
  28.         \ifnum\step<#1 \repeat%
  29.         #1=\t \relax%
  30. }
  31. \def\ifprime#1{ %素数なら0,合成数なら1をjudgeに格納
  32.         \ifnum #1<2 %
  33.                 %1
  34.         \else%
  35.                 \newcount\judge \judge=0 \relax%
  36.                 \newcount\step \step=2 \relax%
  37.                 \newcount\max \max=#1 \decrement\max \relax%
  38.                 \loop%
  39.                         \newcount\temp \temp=#1 \relax%
  40.                         \surplus\temp\step \relax%
  41.                         \ifnum \temp<1 \judge=1 \fi%
  42.                         \increment\step \relax%
  43.                 \ifnum \step<\max \repeat%
  44.                 %\the\judge
  45.         \fi%
  46. }

  47. \begin{document}
  48. \newcount\p \newcount\q

  49. \p=5 \q=3 
  50. \powercalc\p\q
  51. $5^3= \the\t $

  52. \p=5
  53. \function\p
  54. $5!= \the\p $

  55. \ifprime{51} 
  56. if $51$ is prime number? \ifnum \judge<1 Yes. \else No. \fi

  57. \ifprime{53} 
  58. if $53$ is prime number? \ifnum \judge<1 Yes. \else No. \fi

  59. \end{document}
コメントアウトを手作業で赤くするのが疲れてきたのでやめた。
ちなみに各行の最後がコメントアウトしてあったりちょいちょい数値の後に\relaxが入ってるのはバグ防止。どっかで読んだ。

前回作った剰余演算子とインクリメント、デクリメント、減算演算子も冒頭で記述してあるが今回はインクリメントくらいしか使っていない。

累乗、階乗は戻り値がカウンタに格納されて帰ってくるので第一オペランドはカウンタでないといけない。累乗の第二オペランドと素数判定は数値でもカウンタでもいい(はず)。
55行目で5^3、60行目で5!、62,65行目で51と53が素数かどうか判定している。\ifnumで入れた数値が素数かどうか(\judgeが0かどうか)の判定でYes.かNo.か分岐。

実行結果はこう

上手いこと行った。

2ケタ以上の数は{ }で括らないといけないのでカウンタのほうが楽そう。どうせ使うのはマクロの中だろうし。

配列がないので素数のリスト化とかはできず速度のこととか全く考えてないから大きい数だととてもつらい予感がする。ただベンチマークしようにも時間取得が分単位とかだから結構大変かも。
とりあえず平方根関数を使ってStep数を減らすのが当面の課題か。(でも一から実装すると平方根って2分探索とか始まったりしてやばそう。)
いつか配列を使って素数リストを書き出せるマクロでも作りたい。頑張れば連想配列のようなものができるらしいし。

-2019-03-12: \(\TeX\)を\(\mathrm\TeX\)に変更

0 件のコメント:

コメントを投稿