JavaScript 数値演算

提供:yonewiki

JAVA Script#リファレンスに戻る。


Mathオブジェクトには、通常の科学技術計算を行うための関数が準備されていて、便利なものになっています。むろん、MaximaRのようなコンピュータ支援による数式システムや確率統計演算システムには遠くおよばないものです。まだまだ解明されていない数学の世界に挑戦していくこともできるのですが、まずはコンピュータと数学の間にある問題を理解せねばならないでしょう。コンピュータの特徴は有限の小さなメモリを使う変数という性質特有の桁あふれや、精度限界、2進数による表現のためにおこる2進数特有の循環小数の発生について理解しておく必要があり、さらには我々人間が理解しやすい10進数への変換時における文字列表現的数値の表示限界の問題や数値の切り落としのような様々な特徴を理解する必要があります。とはいったもののコンピュータの演算精度と演算速度は人間を楽しませるためには十分な速さと正確さを持っています。うまく使いこなすことで、人間には到底不可能な制御や時間的経過と次に起こることの予測などをしての補正計算に使うことが出来ますし、延々に人間のコントロールするマウスの座標や動きを予測したり、ブラウザ上で動かされたマウスの軌道計算や走行距離、速度をはかることもできます。こういったマウス座標の動きから、通常はありえないペンタブレットを使った場合の座標飛びを検出したり、画面座標計算を駆使することで、ゲームを作ったり、様々な情報提供を行い行動観察やそれを使った様々な指標の提供など、数学が陰ながら社会を支えている技術を提供できます。


※現在、管理人は、この章の説明をするにあたり、やはり、wikiの記事内で美しい数式の記述ができる技術の導入が必要ではないかと思いまして、MathJaxという技術をwikiに導入できないか検証中です。つまり、自作Extension作成中ということです。意外と日本人でMediaWikiのExtension解説サイトをやっている人っていないんですね。あまり得意とは言えない英語ばっかり読んでいて、あたまがおかしくなりそうです。この調子だと年が明けそうです。ウソウソ。そんなに努力家じゃないです。逃亡してます。4か月も放置してればきっとね。


定数

円周率 \( \pi \) Math.PI

直径1の円の円周の長さが \( \pi \) です。面積は半径\( r \) に対して\( \pi r^2 \)となることがわかっています。およそ3.14くらいだとされています。具体的には


$$ \pi = 3.141592653589793 $$


となります。現代ではコンピューターによっておよそ10兆桁まで計算されています。およそで丸め込んでいいような桁数ではありませんが、およそです。どうなってんだ円の長さって?思うんすけど、謎の比率なんですね。直径から円周の長さを求めようとした人間が愚かだったのかもしれないが、終わりなき戦いが続いている。何のためにそこまで計算するのか?そこに延々と続く数字があるから…人間は追いかけ続ける。と、しかいいようがない。個人のPCでもプログラム次第ではギネス記録を達成できる可能性はあるらしい。1年くらい無停止で動き続けるPCが必要です。どうやって申請するのかが不明ですが、10進数で100兆桁分くらいの二進数\((\)8000兆桁くらいか?\()\)が刻み込まれたハードディスクを提出すればいいのかな?紙に出力するとかろうじて数字が読み取れる大きさの数字フォントにしたとしても地球を330周くらいする距離になるそうです。    

 

ネイピア数 \(\mathrm{e}\) Math.E

自然対数の底として \(\mathrm{e}\) が定められていて、この値は2.71くらいです。具体的には、


$$\mathrm{e} = 2.718281828459045 $$


です。対数とは、大きな数同士の積の計算を和の計算に還元するものです。指数同士の積を対数表を用いて和の計算として扱うことができます。正直なところ底はなんでもよかったんですが、オイラーさんによって、とても美しい無理数としてのネイピア数の発見に至った$($具体的には対数の基礎をネイピアさんが考えて、弟子のアウトレッドさんが最初の対数表を作成し実用化、その後、ベルヌーイさんがネイピア数にたどり着きライプニッツさんがこのネイピア数に記号を付与したりして、オイラーさんが具体的に活用し、\( \mathrm{e} \)という文字を割り当て命名したとなっています。そして、このネイピア数を底に自然対数を使い始めたのはメルカトルさんらしいです。本当かどうかは自分で調べてください。\()\)のです。今では対数の底といえば、この数を使うというのが一般的になってきています。 \(\mathrm{e}^x \) を \( x \) で微分\((\)ある数の底の指数値を微分して傾きを計算しても、その数の指数値になるような数\()\)しても \( \mathrm{e}^x \) となる数です。この値は対数の仕組みを使って積の計算を和の計算に還元する手法を一番最初に提案したネイピアさんをたたえるべくネイピア数と命名されています。    

自然対数 \(\log_{\mathrm{e}} 2 \),\( \ln{2} \) Math.LN2/\(\log_{\mathrm{e}} 10 \), \(\ln{10} \) LN10

$$\log_{\mathrm{e}} 2 = 0.6931471805599453 $$


です。つまり、これは対数を指数表現に意味を訳すると


\(\mathrm{e}^{0.6931471805599453} = 2 \) ということです。だから何?とか考える必要はありません。\(\mathrm{e}\) を底とする世界の表現値で2を意味する値が\(\log_{\mathrm{e}} 2\)であり、0.6931を和として利用することで大きな数の積の問題を解決できるということを考えればそれでよいのです。大きな数字の積の計算を和の計算に還元しようとするのが目的であると思えば、対数のややこしい数値的な意味をイチイチ計算しなおす必要はないのです。対数を使うときってのは、計算結果はだいたいが求まれば十分なのです。だいたい。そのだいたいの計算でもとめた値で十分、役にたつし、コンピュータやらに対数表らしきものを使って計算させておけば、人間に役に立つ形式の解が得られるのです。


$$\log_{\mathrm{e}} 10 = 2.302585092994046 $$


で、念のため、訳しちゃうと


\(\mathrm{e}^{2.302585092994046} = 10 \) となります。考え方は先に述べたとおりです。  

 

常用対数 \(\log_2 \mathrm{e} \) Math.LOG2E/\(\log_{10} \mathrm{e} \) LOG10E

先の自然対数の底が $ \mathrm{e} $だったのに対して、常用対数は、それ以外の値を底とする対数です。先の項目でも底はなんだってよかったと書いたのですが、そういうことなのです。ただし底が1だと指数法則的にも、全く役に立たないことになってしまいます。1を何乗したって、1ですから大きな数字を表したりするのには向いていないことは自明です。0もそうです。


底が10の常用対数は初等教育なんかで、対数を理解するためによく使われているかもしれません。やっぱなんだかんだいって無理数のネイピア数では対数の具体的な計算には向いていないっていう。でも、常用対数できっちりとした答えを求めることばかりを教えるから、対数のありがたさや本当の役割を見失って、対数を理解できないまま終わってしまうような気がしています。でも、常用対数の具体的な活用方法もあるっちゃあるわけで、それを知るっていうのも大事なのかなって思います。ちなみに


$$\log_2 \mathrm{e} = 1.4426950408889633 $$


また、対数を指数表記表現に訳すると


\( 2^{1.4426950408889633} = \mathrm{e} \)となります。


更に

$$\log_{10} \mathrm{e} = 0.4342944819032518 $$


またまた、対数を指数表記表現に訳すると


\( 10^{0.4342944819032518} = \mathrm{e} \) となります。常用対数でネイピア数を表現するという、これらの定数ってどれくらい需要があるんかな?やっぱオレにはわかんねぇ。  

 

平方根\( \sqrt{2} \) Math.SQRT2/\( \frac{\sqrt{2}}{2} \)SQRT1_2

\( \sqrt{2} \) は2乗したら2になる数です。つまり、\( \sqrt{2} \times \sqrt{2} = 2 \) です。

したがって、

$$ \sqrt{2} = 1.4142135623730951 $$

というような値になります。1.414を2回かけると1.999396になります。完全に2にはならないけど、桁数を増やしながら、2乗していくと近づいてる実感が得られると思います。ものすごい桁数をコンピュータは定数として覚えています。オレには覚えらんないね。


その半分の値

$$ \frac{\sqrt{2}}{2} = 0.7071067811865476 $$

も定数として使えるようになっています。何に使うんかな?そんなに頻繁に使うんだっけか?やっぱ、死ぬほど苦労してでも東大いっとけばよかったなぁ。事の重大性がわからない。死ぬほど苦労しても行けてなかっただろうけどね。就職氷河期に就職できただけでもよかったと思うことにしよう。  

 

サンプル

<HTML>
<HEAD>
<TITLE>JavaScript Math 定数</TITLE>
</HEAD>
<BODY>
JavaScript Math 定数<br />
<SCRIPT Language="JavaScript">
<!--
document.write("Math.PI = ", Math.PI, "<BR />");
document.write("Math.E = ", Math.E, "<BR />");
document.write("Math.LN2 = ", Math.LN2, "<BR />");
document.write("Math.LN10 = ", Math.LN10, "<BR />");
document.write("Math.LOG2E = ", Math.LOG2E, "<BR />");
document.write("Math.LOG10E = ", Math.LOG10E, "<BR />");
document.write("Math.SQRT2 = ", Math.SQRT2, "<BR />");
document.write("Math.SQRT1_2 = ", Math.SQRT1_2, "<BR />");
-->
</SCRIPT>
</BODY>
</HTML> 


MathJaxとCanvasによるグラフ描画サンプル

こういうのを、MediaWikiの中に埋め込みたいらしい。難しいかな。 みんなで編集するわけじゃないから、ガシガシのExtensionになる予定。

   

       

追記160314

やればできるってことですね。MathJaxが記事中で使えるようになりました。よかった。Texと微妙に違う表記に若干戸惑いますが、そのうち慣れるでしょう。グラフも書きたいからcanvasも頑張ろう。ymathエクステンションを作るのに3日間もかかった。能力や開発効率の低さ。まだまだだなオレ。もう歳だし。無理なんだろうな。超絶やべく頭悪いのは心残りだ。もっと訓練しねぇとなぁ。若いみんなはオレみたいになんなよ。オレなんか軽く超えていってくれたまえ。プログラムの能力を身に着けて近い将来に年間10億かせいでやるぐらいの強い気持ちで強烈に挑んでほしい。


追記160315

canvasもできるようになったぜ!オレってなかなかExtension開発のセンスあんのかな。フフフ♪



ちなみに、記事中にJAVA SCRIPTを埋め込むのは非常に危険な行為でして、ちゃんと動作確認をしてから張り付けないと、やえもすると、その記事のページが表示できなくなってCMSを使っての編集ができなくなることもあります。また、不特定多数で記事の編集をしている場合、JAVAスクリプトに悪意あるコードを埋め込むことによって、Webサイト全体が簡単に書き換えられる可能性もあります。危険なことです。このwikiがハッキングされたら、全部消えることもありえます。覚悟は必要です。バックアップはとってありますので、ある時点に戻るという感じの被害になるのと、もうJAVAスクリプトの埋め込みはやめるという決断とかをするのかもしれません。yjavascriptタグは非常に危険なエクステンションですね。ymathタグは数式を表示するだけなので、たいしたことないっすかね。


てか、記事を読んでJAVA SCRIPTを勉強している人にとってはどうでもいいことですね。

関数

三角関数 sin/cos/tan/asin/acos/atan/atan2

数学関数の中でも、授業中にならった事の他に、意外な楽しさがあるのが三角関数だと思います。半径1の円を横に置きましたが、sin波およびcos波は出発するタイミングこそ違いますが、同じような波を描くように変動します。ちなみにsinはサイン、cosはコサイン、tanはタンジェントと称します。

以下のグラフ$($デカルト座標表示$)$は、

  • \( y = \sin{x} \)
  • \( y = \cos{x} \)

のグラフです。

単調増加関数を示す1次式や、放物線を描く程度の2次式とは違った面白さがあります。xの3乗を含むような3次式もしくはそれ以降の次数になると同じような振動部分がグラフ上で確認できますが、複雑過ぎるという部分があります。sin関数やcos関数は、これだけで振動をする関数としてふるまうところが面白い。


何が?


いや、それがその~、シンセサイザーって波を重ねることで音が出てたりして、その基本波形の一つが、この波なのです。実際は電気信号の振幅ですのでy軸は電圧になりますが、この電圧の振動をスピーカーでコイルを使ってスピーカーコーン部分の振動に変換して音を出すことができるわけです。そういう意味で三角関数は音楽とも関係があるし、角度を距離から計測したり、角度から距離を算出することができるという性質をもっていますし、波形操作のためのいろいろな公式を覚える楽しさと複雑さがとなり合わせになっています。倍角の公式や3倍角あるいは2分の1倍角の公式。加法定理による手計算によるsin α の値の算出へ挑んでいける楽しさ。既に計算済の三角関数表が存在していてコンピュータによっていくらでも計算できる面白さ。そういうことです。そしてフーリエ変換へと飛翔していくのです。そういうことです。


ところで、波になるとかわけわからんこといってるけど、sinって何?cosって何?tanって?ふむふむ。その説明はなかなかWeb上で説明するのは難しい。また図をかかなければならないですね。上図のグラフで半径1の円を描いたつもりでしたが、その円周の適当な位置と円の中心を線で結ぶと、右側のx軸を0度として円周の適当な位置の角度αが決まります。これのsin αってのが、その円周の適当な位置からx軸と平行な線をひいたときにy軸と交わった位置のyの値がsin αの値になります。そして、同じような円周の適当な位置からy軸と平行な線をひいたときのx軸と交わった位置のxの値がcos αになります。当然。cos 0 は、1という値になります。また cos α および sin α は -1~1の間の値にしかなりません。


tan αはx = 1のy軸に平行な線と円周の適当な位置と中心線をとおる直線が交わる位置のyの値となります。tan 90度(直角)のときは、延々にx=1のy軸に平行な線と交わることはないので、値は∞となります。


上記説明を図で示しsin、cos、tanの仕組みを理解できれば三角関数の基礎を理解できたことになりますが、図の描き方によって理解度がかわりますので、ここが腕の見せ所になるわけです。言うやすし、見せるは難しというところです。これが理解できれば、学校の試験とか授業でも、良い成績というかよい理解が得られて、いくらかは三角関数の理解が深まっていたのにと思う人も多いのだと思います。


そのことを明示した図は以下のFLASHコンテンツ swfアニメーションで示しました。左下隅の黒三角の再生ボタンでsin cos単心円(半径1)連動波形アニメーションが開始されます。 <oflash file="" caption="SinCosTan単位円解説 for UploadWiki" width=700 height=120 /> 単位円を上下に青い線が伸び縮みしているのがsin値で橙色の線が伸び縮みしているのが、cos値になります。本来は半径を示す斜めの線との比率が、それぞれの値なのですが、半径が1なので分母が1になるため、それぞれの青い線や橙色の線の長さそのものが、sinやcosの比率値になるわけです。tan値は示しませんでしたが、これも半径が1であるため、x=1や-1の線上と斜めの線が交わる部分の縦の長さこそがtan値になるわけです。これでお分かりいただけないのなら、わたくしめに説明するのは、もう無理です。違う勉強会に参加してみて下さい。


  • sin = 正弦せいげん
  • cos = 余弦よげん
  • tan = 正接せいせつ

と日本語では、このように命名されています。


ちなみに、プログラムではsin xのxに任意の値を与えるだけで、その値を返してくれる便利な関数ですが、xに与える値は角度ではありません。角度を円周の長さで表した円弧の値。ラジアンと呼ばれる単位で与えます。円周の長さは半径1の場合、直径と円周率の積が円周になりますから360度の場合は



$$ 360[度] = 2 \times \pi $$



です。そうすると、1度あたりのラジアン値ってのは、円周を360分割した長さですから360で割って



$$ 1[度] = \frac{2 \pi}{360} = \frac{\pi}{180}$$



になります。本来、掛け算の記号は省略することになっていますので、上記では表記をきちんと省略しました。んで、約分もね。約分は2分の360ってのは1分の180だから、割り切れる部分を残さないっていう記述をできるだけ簡素化する決まりのことです。任意の角度N[度]に対して、ラジアンに変換する場合は


$$ N[度] ←変換→ \frac{\pi}{180} N[rad]$$


だね。ここまで言わなくていいよね。って人に教えるときには、相手を見て言うことがあるのですが、こないだ、「あとはもうわかるでしょ。」と教えることを切り上げると、おもいっきり逆切れされたことがありまして、「だから、あたまのいいやつの教え方はあかんねん。もう教えてイラン!」とか言われました。「ええええええ!」ってなりましたが、相手の気持ちってのはわからないもので、これ以上は失礼だとおもって、教えるのを切り上げると、ブチ切れられることを知りました。あとはもうっていわれても、その先もわからないときは、イライラする人もいるみたいです。相手の様子を見て、最後まで教えきるのが大事なのです。わかっている人にはウザいかもしれません。ここが教えるときの塩梅$($あんばい$)$の難しさです。頭がいいと思ってくれるのは勝手ですが、自分自身では、ちっとも頭がいいとは思いません。学問の道は果てしないく崇高なところまで道が続いていて、そこにはたどり着けていないと感じています。だいたいの人がそうなんだと思いますが、あるところを境にして、俺は頭がイイと断言できるようになることもあるらしいというのが人間界の思想のようです。どこを境にしているかは個人の自由なのですが、あまりにもおかしなところを境にしている人もいます。ポジティブっていいね。自分みたくネガティブな人はどこまで勉強しても境を超えられませんけどね。でも、気持ちはポジティブですよ。楽しいこと考えたりするの好きだし。運が悪いとかはあまり考えないようにしている。運は自分でつかんでいくものです。確率をあげていくのは自分自身の努力によってもできることがあると思います。やれる範囲が限られているから、客観的にみて運が悪いという結果にはなっているんだと思います。宝くじも毎回のように大量に買い占めれば当てれるわけですし。少しの投資を莫大なものに変える運もなにか努力をすればなんとかできるような気もします。不正はだめですけどね。考え方次第です。


脱線しました。


なので、各関数の引数は半径1の弧の長さを示す[rad]ラジアンという単位を使います。何?ラジアンって?と言われると困りますがラジアンはラジアンです。ラジアルとはあまり関係ないです。ややこしいだけです。有名な女芸人コンビのアジアンとも関係ないです。


ところで、sin、cos、tanは具体的にはどういう風に役に立つのでしょうか?まずは、角度はわかっているけど距離がわからないときの活用について考えましょう。そんなことは、コンピュータの世界ではほとんどありえませんけどね。逆の方が多いでしょう。でも例えば、45度のななめの線の距離を知りたい場合なんかに役に立ちます。x軸上に延びた横の線の長さは120pxだったとしましょう。さて、45度の斜め線はおよそ何pxに相当する長さでしょうか?知りたい長さを r とすると


$$ \sin({45 * \frac{\pi}{180}}) = \frac{r}{120[px]} $$


で、求まります。45度の場合は誰がどう考えたって\(\sqrt{2} * 120|\)じゃん。って想像がつきますかね。ピタゴラスの定理で1:1:\(\sqrt{2}\)だもんね。上記の式でもrの方程式を解くと同じ事になります。それは\(\sin({45 * \frac{\pi}{180}}) = \sqrt{2}\)になることを知っているのと同じことです。いやはや。で、45度以外の場合はどうでしょう?コンピュータに計算してもらった方が早いっすね。ま、そういう使い方をします。縦の長さだけがわかっている場合はcosを利用したり、斜めじゃなくて、x軸あるいはy軸のどちらかの長さがわかっていて、角度だけがわかっている場合なんかには、そのわからない方をtanで求めることができます。tanはx軸とy軸の関係を角度から算出できるのでコンピュータでは、頻繁に利用します。


そして、sin、cos、tanにおいて角度がわからない場合に使うのが、asin、acos、atanあるいはatan2です。それぞれアークサイン、アークコサイン、アークタンジェントあるいはアークタンジェントツーというのが正式な呼び方になるでしょうか?たぶんそういう意味でasinと関数名を略している思います。これは数式で表現するなら、


$$ \arcsin \frac{141[px]}{100[px]} = 45 \frac{\pi}{180} = 0.78539816339744830961566084581988...$$


という結果が得られます。つまり比率から角度を求める逆の関数です。昔は


$$ \sin^{-1} (\frac{141[px]}{100[px]}) $$


のように表記してましたけど、最近は見なくなりましたかね。ちなみに三角関数の算出値の比率による角度の解は複数の解を持つし、一回転以上させた値も含めると∞の解が存在します。これでは、結果を返すことができないので、主値というものを返却するあるいは主値に制限されることとしています。簡単に言うなら小さい角度の解が得られるということです。それを見越して演算する必要があります。


atan2関数は引数を二つとる関数になっています。通常はY軸となる高さをX軸となる幅で割った値をatan関数の引数として角度を算出するのが、アークタンジェントの計算になりますが、そういった算術式を引数としなくても、atan2関数は第一引数にy軸方向の値、第二引数にx軸方向の値を与えると、その長さに対応する角度の値をラジアンに相当する値として答えを返してくれる関数です。具体的な関数の利用方法についてのサンプルは後述のとおりとなります。


サンプル


<HTML>
<HEAD>
<TITLE>JavaScript 三角関数</TITLE>
</HEAD>
<BODY>
JavaScript 三角関数<br />
<SCRIPT Language="JavaScript">
<!--
document.write('<TABLE BORDER="1" cellspacing="0">\n');
document.write('<TR>\n');
document.write('  <TD>[度]</TD><TD>sin</TD><TD>cos</TD><TD>tan</TD>\n');
document.write('</TR>\n');
for(var i = 0;i <= 360;i++){
document.write('<TR>\n');
   document.write("  <TD>", i, "</TD><TD>", Math.sin(i * Math.PI /180), "</TD><TD>", Math.cos(i * Math.PI /180), "</TD><TD>", Math.tan(i * Math.PI /180), "</TD>\n"); 
document.write('</TR>\n');
}
document.write('</TABLE>\n');
-->
</SCRIPT>
</BODY>
</HTML>

サンプル実行結果

サンプルは三角関数表を出力するものですが、ものすごい桁数まで、コンピュータの限界に迫る計算結果になっています。tan 90度は一般には∞という解になるとされていますが、javascriptではvar i変数の最大値を返却します。また、sin360やtan360も0になるはずですが、引数に渡す値が360度のラジアン値であるため、πを使って算出していますが、Math.PIが近似値であるために、完全には0になりません。このような問題を解決するのが四捨五入や切り捨てや切り上げという考え方があります。このことについては後述の項目で、説明できる機会がありそうです。それまでは、このぐちゃぐちゃとしたみたこともない三角関数表を楽しんで頂ければと思います。ここまで計算できるという限界や誤差の発生パターンを知るのも大事だと思います。

最小値・最大値 max/min

例えば、3,-1,13,5,9,25,-0.51,3.9,9.9といった数字の集まりがあった場合に最大値と最小値ってのは、人間が目視ですぐに、 最大値が25で最小値は-1だと言えますが、コンピュータがそれを見つけるにはなかなか地味な作業を繰り返さなければ、最大値を正確に返答することができません。地味に最初に表示されている3が最大として、次の数字と比較してどうなのかを確認しながら最後までチェックするのです。最小値も同じことです。人間は一瞬みただけですぐに最大、最小が判別できますが、何気に高度な比較をやっていることもあります。しかし、これが数字の羅列が1万や10万という個数になった場合にもコンピュータは間違いなく、最後まで比較をやって答えを正確に導き出せるという人間技からは到底考えられない地味な働きを行うことができます。間違えないという点では、コンピュータには勝てないかもしれません。途中にでてくる-0.51という数字があるだけでも一瞬、-1との比較で間違えそうになるかもしれません。


MAXはミナ、ナナ…ちがった。maxはMaximum、minはMinimumの略だと思われます。


ともかく、そういった作業をするための関数がMath.maxであり、Math.minです。自分でプログラムして大きい値がどっちか、小さい値がどっちかを求めるものを作ることも可能ですが、関数としても提供されています。コーディング量が節約できるので、うまく活用するのも良いと思います。


例えば、以下のように記述することで、比較ができます。

  • var nMaxTemp = Math.max$($3,-1$)$;
  • var nMinTemp = Math.min$($3,-1$)$;

という具合です。多くの数の中から最大、最小を求める場合は以下のサンプルのようにプログラムを組む必要があるでしょう。


サンプル


<HTML>
<HEAD>
<TITLE>JavaScript max min</TITLE>
</HEAD>
<BODY>
JavaScript max min<br />
<SCRIPT Language="JavaScript">
<!--
var prevNumber = "";
var arrNumber = new Array(3,-1,13,5,9,25,-0.51,3.9,9.9);
document.write("配列arrNumber=");
for(var element in arrNumber){
    if(arrNumber[element] != ""){
        if(prevNumber == ""){
            prevNumber = arrNumber[element];
            nMaxTemp = prevNumber;
            nMinTemp = prevNumber;
        }
        else{
            prevNumber = arrNumber[element];
            nMaxTemp = Math.max(nMaxTemp, arrNumber[element]);
            nMinTemp = Math.min(nMinTemp, arrNumber[element]);
        }
    }
    document.write(arrNumber[element], ",");
}
document.write("<BR />\n");
document.write("最大値 = ", nMaxTemp, "<BR />\n");
document.write("最小値 = ", nMinTemp, "<BR />\n");
-->
</SCRIPT>

</BODY>
</HTML>

サンプル実行結果


ちなみにMAXのもう一人はレイナさんですね。はい~v$($・-・$)$v♪

絶対値 abs

絶対値って?難しくないです。幅の長さ、みたいなもんです。え?幅?長さ?。そう、マイナスの概念が存在しない世界です。あそこからあそこまでの幅はいくら?って感じです。それが絶対値。どういうこと?例えば大阪を基点に東京は500km、広島は-300kmと数値が与えられたとします。で、広島までの長さは?となると絶対値の-300kmと表現します。つまりは300kmです。それだけのことです。


人間が言葉で表すのは簡単な事です。マイナスがついていたら、マイナスをとるという作業を何の気なしにやってると思います。数学的に表現すると絶対値の-300kmは以下のように記述します。


広島までの幅の長さ[km] \(= | -300 \times 10^3 |\)


そして、大阪を基点とした距離l$($小文字のエル$)$[km]が与えられたとして、幅の長さd$($distance$)$[km]はどう表すかというと


$$d \times 10^3 = | l \times 10^3 |$$


です。それをプログラムで表現すると


  • Math.abs(l * 1/(10 * 10 * 10))


ですね。absはアンチロックブレーキシステムです。違う。absはアブソリュート:absoluteの略です。


サンプル

<HTML>
<HEAD>
<TITLE>JavaScript abs</TITLE>
</HEAD>
<BODY>
JavaScript abs<br />
<SCRIPT Language="JavaScript">
<!--
var nDiff = Math.abs(1000 - 7100);
document.write("絶対値 |1000 - 7100| = ", nDiff, "<BR />\n");
-->
</SCRIPT>

</BODY>
</HTML>

サンプル実行結果

切り捨て・切り上げ・四捨五入 floor/ceil/round

切り捨て、切り上げ、四捨五入。聞いたことある言葉であってほしいです。切り捨てとは、能力のないと思われた人が、偉い人から会社を追い出されるようなことです。この例え、なんか違うな…えっと切り捨てとは、8:00発の満員電車の押し込まれて乗車しようとしたものの扉がどうしても閉まらず、取り残されるようなことです。う~ん、これも違うな。切り捨てとは、例えば、会費が4500円の飲み会があったとして、2年目以内の新人さんは1000円より少ない額については切り捨て、4000円でいいよ!と、500円を免除されるようなことです。小数点以下の値で切り捨てがされることも多いですが、大きい位でも切り捨てはされます。いらない人間はいないので人間が切り捨てられることはありません。切り捨てではなく、社会構造上の問題による組織編成の変更であり、捨てたわけではないのです。捨てた捨てられたと思う人もいるかもしれません。新しい世界が待ち受けているハズなのです。自分の能力を信じるしかありません。ポジティブに!って無理があるか…。現実はそう甘くない。切り上げは、例えば10個入りのお菓子を買う場合、42人全員に1個以上のお菓子を割り当てる必要がある場合にお菓子は50個買わなければならず、人数に応じて、ある区切りを超えたら、とにかく多く準備しなければならいようなケースです。


四捨五入は伝統的な近似表現で、ある位に注目して4以下なら切り捨て、5以上なら切り上げるという手法です。このように切り捨て・切り上げ・四捨五入には、処理を行う数値と、どこの位で切り上げや切り捨て、四捨五入をするのかを指示する必要があるのですが、用意された関数にはどの位でそれを処理するかという指示はできなくて、すべて小数点第一位を対象に実施されます。したがって、一の位を対象にしたい場合は10分の1の値にしてから切り上げ・切り捨て・四捨五入を行い、その後10倍するというやり方になります。


<HTML>
<HEAD>
<TITLE>JavaScript floor,ceil,round</TITLE>
</HEAD>
<BODY>
JavaScriptvz floor,ceil,round<br />
<SCRIPT Language="JavaScript">
<!--
function funcFCR(strMode,nValue,nPower){
    strMode = strMode.toLowerCase();
    if(nPower <= -1){
        fReturn = nValue * Math.pow(10,-1 * nPower - 1);
    }
    else{
        fReturn = nValue * Math.pow(10,-1 * nPower);
    }
    switch(strMode){
        case 'floor':
        case 'f':
            fReturn = Math.floor(fReturn);
            break;
        case 'ceil':
        case 'c':
            fReturn = Math.ceil(fReturn);
            break;
        case 'round':
        case 'r':
            fReturn = Math.round(fReturn);
            break;
        default:
            return nValue;
    }
    if(nPower <= -1){
        fReturn = fReturn * Math.pow(10,nPower + 1);
    }
    else{
        fReturn = fReturn * Math.pow(10,nPower);
    }
    return fReturn;
}
var nValue1 = -7123;
var nValue2 = 6655;
var nValue3 = 21.4
document.write("<BR />\n");
document.write(nValue1, "<BR />\n");
document.write(nValue1, "(十の位で切り捨て) = ", funcFCR('floor',nValue1,2), "<BR />\n");
document.write(nValue1, "(一の位で切り捨て) = ", funcFCR('floor',nValue1,1), "<BR />\n");
document.write(nValue1, "(小数点第一位で切り捨て) = ", funcFCR('floor',nValue1,0), "<BR />\n");
document.write(nValue1, "(小数点第一位で切り捨て) = ", funcFCR('floor',nValue1,-1), "<BR />\n");
document.write(nValue1, "(小数点第二位で切り捨て) = ", funcFCR('floor',nValue1,-2), "<BR />\n");

document.write("<BR />\n");
document.write(nValue2, "<BR />\n");
document.write(nValue2, "(十の位で切り捨て) = ", funcFCR('floor',nValue2,2), "<BR />\n");
document.write(nValue2, "(一の位で切り捨て) = ", funcFCR('floor',nValue2,1), "<BR />\n");
document.write(nValue2, "(小数点第一位で切り捨て) = ", funcFCR('floor',nValue2,0), "<BR />\n");
document.write(nValue2, "(小数点第一位で切り捨て) = ", funcFCR('floor',nValue2,-1), "<BR />\n");
document.write(nValue2, "(小数点第二位で切り捨て) = ", funcFCR('floor',nValue2,-2), "<BR />\n");


document.write("<BR />\n");
document.write(nValue3, "<BR />\n");
document.write(nValue3, "(一の位で切り捨て) = ", funcFCR('floor',nValue3,1), "<BR />\n");
document.write(nValue3, "(小数点第一位で切り捨て) = ", funcFCR('floor',nValue3,0), "<BR />\n");
document.write(nValue3, "(小数点第一位で切り捨て) = ", funcFCR('floor',nValue3,-1), "<BR />\n");

document.write("<BR />\n");
document.write(nValue1, "<BR />\n");
document.write(nValue1, "(十の位で切り上げ) = ", funcFCR('ceil',nValue1,2), "<BR />\n");
document.write(nValue1, "(一の位で切り上げ) = ", funcFCR('ceil',nValue1,1), "<BR />\n");
document.write(nValue1, "(小数点第一位で切り上げ) = ", funcFCR('ceil',nValue1,0), "<BR />\n");
document.write(nValue1, "(小数点第一位で切り上げ) = ", funcFCR('ceil',nValue1,-1), "<BR />\n");
document.write(nValue1, "(小数点第二位で切り上げ) = ", funcFCR('ceil',nValue1,-2), "<BR />\n");

document.write("<BR />\n");
document.write(nValue2, "<BR />\n");
document.write(nValue2, "(十の位で切り上げ) = ", funcFCR('ceil',nValue2,2), "<BR />\n");
document.write(nValue2, "(一の位で切り上げ) = ", funcFCR('ceil',nValue2,1), "<BR />\n");
document.write(nValue2, "(小数点第一位で切り上げ) = ", funcFCR('ceil',nValue2,0), "<BR />\n");
document.write(nValue2, "(小数点第一位で切り上げ) = ", funcFCR('ceil',nValue2,-1), "<BR />\n");
document.write(nValue2, "(小数点第二位で切り上げ) = ", funcFCR('ceil',nValue2,-2), "<BR />\n");


document.write("<BR />\n");
document.write(nValue3, "<BR />\n");
document.write(nValue3, "(一の位で切り上げ) = ", funcFCR('ceil',nValue3,1), "<BR />\n");
document.write(nValue3, "(小数点第一位で切り上げ) = ", funcFCR('ceil',nValue3,0), "<BR />\n");
document.write(nValue3, "(小数点第一位で切り上げ) = ", funcFCR('ceil',nValue3,-1), "<BR />\n");

document.write("<BR />\n");
document.write(nValue1, "<BR />\n");
document.write(nValue1, "(十の位で四捨五入) = ", funcFCR('round',nValue1,2), "<BR />\n");
document.write(nValue1, "(一の位で四捨五入) = ", funcFCR('round',nValue1,1), "<BR />\n");
document.write(nValue1, "(小数点第一位で四捨五入) = ", funcFCR('round',nValue1,0), "<BR />\n");
document.write(nValue1, "(小数点第一位で四捨五入) = ", funcFCR('round',nValue1,-1), "<BR />\n");
document.write(nValue1, "(小数点第二位で四捨五入) = ", funcFCR('round',nValue1,-2), "<BR />\n");

document.write("<BR />\n");
document.write(nValue2, "<BR />\n");
document.write(nValue2, "(十の位で四捨五入) = ", funcFCR('round',nValue2,2), "<BR />\n");
document.write(nValue2, "(一の位で四捨五入) = ", funcFCR('round',nValue2,1), "<BR />\n");
document.write(nValue2, "(小数点第一位で四捨五入) = ", funcFCR('round',nValue2,0), "<BR />\n");
document.write(nValue2, "(小数点第一位で四捨五入) = ", funcFCR('round',nValue2,-1), "<BR />\n");
document.write(nValue2, "(小数点第二位で四捨五入) = ", funcFCR('round',nValue2,-2), "<BR />\n");


document.write("<BR />\n");
document.write(nValue3, "<BR />\n");
document.write(nValue3, "(一の位で四捨五入) = ", funcFCR('round',nValue3,1), "<BR />\n");
document.write(nValue3, "(小数点第一位で四捨五入) = ", funcFCR('round',nValue3,0), "<BR />\n");
document.write(nValue3, "(小数点第一位で四捨五入) = ", funcFCR('round',nValue3,-1), "<BR />\n");

-->
</SCRIPT>

</BODY>
</HTML>

サンプル実行結果


funcFCRという切り捨て、切り上げ、四捨五入を一括で行う関数を作りました。引数は3つ必要です。

  1. モード指定文字列\((\)floor\((\)f\()\),ceil\((\)c\()\),round\((\)r\()\)※大文字・小文字区別無し\()\)
  2. 処理する数値\((\)数値が渡されることを前提としています。数値か?判定してエラーにする処理を追加するとなおよし!性善説プログラムになってます。)
  3. 処理桁位置指定。0と-1は同じにしました。いずれも小数第一位を指定したことになります。


引数は上記のような感じです。 プログラム中では、まだ説明していないビルトイン関数\((\)あらかじめ用意されている関数\()\)を2つほど使いました。powは次の項目で説明します。toLowerCase\((\)\()\)は、文字列変数の中身を小文字にそろえる処理をするメソッド\((\)オブジェクト変数にぶら下がっている関数\()\)です。

平方根・べき乗(累乗根) sqrt/pow

平方根はスクエアルート(square root)べき乗はパワー(power)で表現されます。平方根はある数xを2分の1乗したものだと言えます。つまり、\( x^{\frac{1}{2}}\times x^{\frac{1}{2}} = x^{\frac{1}{2} + \frac{1}{2}} = x \)となって、\( x^{\frac{1}{2}} \)を2回掛けると\(x\)になりますから、まさに\( x^{\frac{1}{2}} = \sqrt{x}\)といえるでしょう。そうするとsqrt関数はpow関数で置き換えることができることもわかったと思います。3乗根は\( x^{\frac{1}{3}}\)のように表現できますから\(n\)乗根は\( x^{\frac{1}{n}}\)となります。そういういみでべき乗を計算できるpowerに累乗根というタイトルを付けました。ちなみに累乗根の手計算は追い込み法という方法で3乗根ならば試しに3回掛けて、目的の値より小さいかどうかを確認していく方法を自分は使いますが、中学校の英語の時間に先生がスキッドの合間の息抜きに累乗根の計算方法というのを大学時代に編み出したと、披露してくれたのですが、複雑すぎて当時は覚えられませんでした。今もう一度教えを乞うことができるのであればもう一度おしえを乞いたいところです。累乗根を効率よく手計算で算出するという技。凄かった。自分もいろいろと考えてみたことがありますが、編み出せません。


数々の数学者が独自に編み出してきた手法を伝説に残しています。わたしはこの累乗根の手計算に意外かつ高効率な計算方法が、英語の先生が考えた以上にスゴイ手法が隠されているのではないかと思っています。でも、累乗根の近似値計算ってとんでもなく大変です。でもコンピュータはあっというまに計算してしまいます。どういうアルゴリズム(手順)が組まれているのか気になりますが、きっと地味な方法で何回も何回も計算してるんでしょう。100乗根とか…近似値を手計算しろっていわれたら、つらいっす。一昼夜はかかりそうです。


べき乗の小数の計算も累乗根の計算との組み合わせによって計算されます。例えば、\(7^{2.93}\)を計算したいとしましょう。これは\(7^{2+0.93}\)と書くことができます。すると\(7^{2+\frac{9}{10}+\frac{2}{100}}\)と表現できます。まぁ、これをコツコツ計算するときっと解にたどり着くんでしょう。あるいは近似値に…。大変です。


なんだか大変そうですが、コンピュータのはじき出す計算結果にだけ頼ってきた自分です。原理だけは知ってるから、コンピュータが計算する結果が正しいと信じよう。信じるとしよう。信じる者は救われる。


ところで\(2^2=4\)です。で、\(2^1=2\)ですかね。じゃ\(2^0\)は?


2を2回かけたら4です。だから、逆に戻っていくとして、4を2で割ったら、\(2^1=2\)です。もう一回2で割ったら?そうです。\(2^0=1\)です。では\(2^{-1}\)は?そうですね。もう一回2で割って\(\frac{1}{2}=0.5\)です。こういう関係性がべき乗の定義となっています。


一応、コンピュータが計算してくれるとは言え、基礎くらいは知っておいた方がいいかと思い、ややこしい説明をしました。スクリプトとして利用するのは簡単です。サンプルは以下のとおりです。


<HTML>
<HEAD>
<TITLE>JavaScript sqrt pow</TITLE>
<!--[if lt IE 9]><script type="text/javascript" src="ExplorerCanvas-master/excanvas.js"></script><![endif]-->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  tex2jax: {
    inlineMath: [['$','$'], ['\\(','\\)']],
    processEscapes: true
  },
  CommonHTML: { matchFontHeight: false },
  displayAlign: "left",
  displayIndent: "2em"
});
</script>
<script async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML">
</script>

</HEAD>
<BODY>
JavaScript sqrt pow<br />
<SCRIPT Language="JavaScript">
<!--
document.write('square root 2 $\\sqrt{2} = ', Math.sqrt(2),'$<BR />\n');
document.write('pow 7の3乗根 $\\sqrt[3]{7} = ', Math.pow(7,1/3),'$<BR />\n');
-->
</SCRIPT>

</BODY>
</HTML>

サンプル実行結果

対数・指数函数 log/exp

ネイピア数のところで少しだけ触れましたが、対数は複雑数値同士の積を指数で近似表現することで、積の計算を和の計算に還元するもので対数表があれば、手計算で和の計算をするだけで積の近似計算ができます。指数部だけでの計算をするために使われるのがlogによる表現です。


そして、その指数の底がネイピア数なのでした。そして、ネイピア数を底とした指数計算をするための関数がexp関数です。


\(e^{x}\)のxに数値を与えて、その値を計算するためのものです。対数表を見ずとも近似値を算出できるわけです。コンピュータって便利ですね。つうか対数なんか使わなくてもコンピュータにやらせたら、なんでも計算できるじゃんと思いました?そうですよね。自分もそう思った時がありました。でも、指数表現する数値は、普段使っている数値とは天文学的に桁が違うわけです。なので、コンピュータがあるからといって、対数を使わないで計算するようなことは資源の無駄にしかなりません。


それが、数学の価値なのです。人間が編み出した効率の良い数値のための仕組みなのです。多少コンピュータのリソースを無駄にするくらいで、わたしのような凡人が抱える問題は解決できることがほとんどです。だから、まぁ無理して使わなくてもいいんですけど、利用するケースは意外とあります。例えば、電力利得とか、音の大きさとかを制御する計算をするときはデシベルという単位を使います。正確にはデシはデシリットルのデシと同じく、量の単位ですので、ベルが単位になります。指数的増加を見せる現象というのは、音の振動やら電気信号やら電波(短波・長波・電磁波・光・可視光・放射線)やら宇宙における各種現象といった具合に案外、身近な自然界に存在しています。


わかったようなわからないような説明ですが、ネイピア数の指数部を独立変数xとした関数を微分しても傾きがネイピア数のx乗という元の値になるという美しい値を持つネイピア数の導出に関する話を省いたり、もっと難しい話は避けてきましたので、もっともっと数学は奥が深いです。基礎の基礎だけ説明させてもらいました。自分が放送大学で勉強したような内容。数列や場合の数、ベクトル、解析幾何、微分、積分、微分方程式、素因数分解、素因数の一意性。もっと踏み込めば、級数展開、行列演算、線形代数、数学の歴史、さらにはゲーテルの不完全性定理、ガロア理論…、フェルマーの最終定理…ラングランズ・プログラム…なんでもは知らないけど、知ってることだけ。せめて微分方程式あたりに到達することで見えてくる数学の面白さのSTART地点くらいまでは導きたいと考えていますが、ソレについては別の記事で説明したいと思います。独自の解釈で間違っていたりする部分もあるかもしれないので、正確にわかりやすく説明できるかが心配ですが、自分の話をまじめに聞いてもらえれば、ちょっとくらいは実際の現場に役に立つ数学知識に変化すると自負しています。


――― \(y = \ln x = \log_e x\)
――― \(y = \exp(x) = e^{x}\)


デカルト座標グラフで関数を図示すると上記のようになります。この2つの関数はx=の式にしたりy=の式に変形するとxとyを入れ替えただけの形をしています。こういう関係性を逆関数といいます。2つの関数にそれぞれa、bと命名するとaはbの逆関数でbはaの逆関数ということです。デカルト座標ではy=xのグラフの線(原点を通る45度斜めの線)を境に線対称になるような図になります。関数を\(f(x)\)の形式で説明すると、とたんになんだかややこしく感じると思いますので、あえてこの表現は今、使いません。対数の値は指数値ですからxが巨大な数値になっても対して大きな数値にはならないことが特徴です。一方でexp関数は自然対数を底とした指数の値なのでxが増加すると巨大な数値になります。増加する割合は変化しませんので極端に大きくなるというか、段々と増えるスピードが速くなるというようなイメージまでは持たなくてもいいと思います。


<HTML>
<HEAD>
<TITLE>JavaScript exp log</TITLE>
<!--[if lt IE 9]><script type="text/javascript" src="ExplorerCanvas-master/excanvas.js"></script><![endif]-->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  tex2jax: {
    inlineMath: [['$','$'], ['\\(','\\)']],
    processEscapes: true
  },
  CommonHTML: { matchFontHeight: false },
  displayAlign: "left",
  displayIndent: "2em"
});
</script>
<script async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML">
</script>

</HEAD>
<BODY>
JavaScript exp log<br />
<SCRIPT Language="JavaScript">
<!--
document.write('Expornential $e^{1} = \\exp(1) =', Math.exp(1),'$<BR />\n');
document.write('自然対数 $\\log_\\mathrm{e} \\mathrm{e} = ', Math.log(Math.E),'$<BR />\n');
-->
</SCRIPT>

</BODY>
</HTML>

サンプル実行結果

乱数 random

乱数には生成方式がどうとか?確率分布がどうとか、そういった細かい議論が起こりますが、なんしか、このrandom関数を呼び出すと0~1の間の適当な値がほぼ無作為に生成されると考えていいと思います。ゲームや音楽、仕組みの中で何が起こるかわからなくするという要素を生み出すための数値生成と言えます。何が起こるかわか内から人生は面白い。運命が決まっているとしても、運命とはどうなっているのかわからないから面白い。生まれた瞬間からすべての未来が正確に予測される人生があったとしたら、それを知ったうえで生きる人生というのは面白いのでしょうか?わからないから面白い。


自分の人生はどこへ向かっているのか?どこから来て、どこへ行くのか?


生きるとは学ぶこと。


学ぶことは未来を変えること。


未来を変えるとは、正確な答えは無い。


だけど未来の方向をある程度の範囲に収めることはできる。


自分はそのように解釈しています。ランダムとはどこへ向かうか限りなく制御できないものです。だからこそ面白さは作れる。もっとちがったことで意思決定をしている人間のランダムとはちがった面白さです。あのひと何を考えているかわからないのときの面白さは知能というものがつかさどっています。そしてソレを計算機で実現しようとする人工知能も面白い。ただし、とちらのわからないも制御できないからこそストレスが生まれることもありえます。不満。戦争。殺し合い。恨み。呪い。制御できないからこそ無数に感情が分岐される。それが平等なのか不平等なのか?わからない。多くの人間が最終的に快感を覚える程度のランダムに関する制御を行うのがプログラムする人の腕の見せ所だと思うのです。人間が不満ばかりをかかえるランダムはあまりいらない。


そのさじ加減が難しいから、ゲームも売れるもの、売れないもの、いろいろと変化します。それくらいランダムは人間の社会生活を変える要素になっているのだと思います。争いが生じてゲームがきっかけで社会的な不幸が発生するのだとしたら、それは情報技術を売る側の怠慢なのではないでしょうか?わからないからこそ結末をある程度予測するということに挑戦し続ける必要はある。


長くなりましたが、そういう重要なことを決める関数です。


使い方は


  • Math.random$($$)$


とすることで、0~1の小数値が返却されます。どういった数値になるかは呼び出すまではわからないことになっています。


乱数で、ある確率に収束する、乱数を生成する場合。自分は10までのn進数法をよく使います。計算は長くなります。


たとえば2進数のビットをすべて乱数で求める仕組みにする場合0~0.5まではビット値0それ以外はビット値1として必要な桁数分だけ繰り返して、2進数値を10進数に変換するなりして、その値によって動作を決定するというような作り方です。10進数でも同じです。値の範囲の取り方をn等分しますので、ここの偏りをつくれば出やすい数値とかが出てしまいます。n等分を均等にするとより分布が安定するかもしれないという予想においては、10進法と2進法による数値決定が一番やりやすいです。スロットなんかでは2進数のビット数くらいの確率で乱数を発生させて動作を決めているので、n進法乱数発生というのを使って、動きを真似してみたりすることを考えたことはあります。


乱数に関する数学的考察はいろいろとありますので、これ以上の複雑な話は別の記事にでも記述したいと思います。分布にはいろいろなものがありますので、一口に乱数といってもいろいろな性質をもつものがあることも頭の片隅においておくとよいと思います。なんなら、乱数 分布で検索してより詳細なことについて確認すると良いでしょう。


<HTML>
<HEAD>
<TITLE>JavaScript random</TITLE>
<!--[if lt IE 9]><script type="text/javascript" src="ExplorerCanvas-master/excanvas.js"></script><![endif]-->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  tex2jax: {
    inlineMath: [['$','$'], ['\\(','\\)']],
    processEscapes: true
  },
  CommonHTML: { matchFontHeight: false },
  displayAlign: "left",
  displayIndent: "2em"
});
</script>
<script async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML">
</script>

</HEAD>
<BODY>
JavaScript random<br />
<SCRIPT Language="JavaScript">
<!--
for(var i=0;i < 1000;i++){
  document.write('乱数値 random ', i, '=', Math.random(),'<BR />\n');
}
-->
</SCRIPT>

</BODY>
</HTML>

サンプル実行結果


 

 

JAVA Script#リファレンスに戻る。