JS 対数

コード

[JSの小ネタ] 常用対数をどう扱う

JavaScript で常用対数を扱おうとしたときのメモ書きです。

普段の生活に対数がどれほど登場するか微妙ですが、化学系に関連していることであれば、探せば普通にあります。
関数電卓のごとく簡単に書くことを前提としていましたが、当時は参考にするものが少なく原始的な方法で行っていました。

JavaScript で自然対数を扱う

当然ですが、自然対数が扱えない言語はごく少数です。JavaScript はもちろん扱うことができます。

自然対数

上の「e」を底とする対数が自然対数で、JavaScript では

// Math.log(x)
var num = Math.log(20);

と書きます。xに求めたい数字を入れるだけですが、負の値を入れると NaN(不可)になります。
log() は Math オブジェクトの静的メソッドで、常に Math.log() という形で使用します。

JavaScript で常用対数と二進対数を扱う

一般的には自然対数より常用対数を使うことの方が多いと思います。
Math クラスでは次のような常用対数に使える定数が定義されています。

Math.LOG10E    10を底とする <em>e</em> の対数
Math.LOG2E     2を底とする <em>e</em> の対数

これを用いて、常用対数は
常用対数
を利用して書きます(私は昔そんなことをやっていた)。

// 234,567,890,123 の常用対数を求めるときは
var num = Math.LOG10E * Math.log(234567890123);
// Math.LOG10E * Math.log(234567890123) = 11.37026856150149

というような感じです。
二進対数の場合は、
二進対数
を利用します(あくまで過去の話です)。

// 33,554,432 の二進対数を求めるときは
var num = Math.LOG2E * Math.log(33554432);
// Math.LOG2E * Math.log(33554432) = 25

JavaScript でスマートに常用対数と二進対数を扱う

実のところ上の方法で問題なく使ってきたのですが、いざというとき素早く式を書き換えたいときなど、式がシンプルでないとバグを誘発します。気をつけていれば問題ない、関数化していれば問題ないのですが、もっとシンプルに書く方法がありました。

JavaScript で常用対数と二進対数をシンプルに扱う

// 234,567,890,123 の常用対数を求めるときは
var num = Math.log10(234567890123)
// Math.log10(234567890123) = 11.37026856150149

// 33,554,432 の二進対数を求めるときは
var num = Math.log2(33554432);
// Math.log2(33554432) = 25

冷静に考えれば、この程度の関数はあって当然なのですが、無いものと思い込んでいたため10年以上もダサい方法で処理してきました。それでも問題はなく、あまり対数を使わなかったからというのもありますが、特に気に止めなかったというのがホントのところです。

ここで問題です、多くの場合は問題がないのですが、この二つの対数を計算するときは全く同じ値になるのかと言えば、そうでもないのです。

// 234,567,890,123 の常用対数を求めるときは
var num1 = Math.LOG10E * Math.log(234567);
var num2 = Math.log10(234567)
// Math.LOG10E * Math.log(234567) = 5.3702669134658<span class="rmarker">585</span>
// Math.log10(234567) = 5.3702669134658<span class="rmarker">59</span>

小数点第9位までは同じですので、実用上問題はなさそうですが、関数内部の数字の丸め方の差も出るようです。
また、むやみやたらに数式に放り込むようなことをすると、望んでいる数値が得られないことがあります。
たとえば、

// 234,567,890,123 の常用対数を求めるときは
var num1 = Math.log(1000) / Math.log(10);
var num2 = Math.log10(1000);
// Math.log(1000) / Math.log(10) = 2.9999999999999996
// Math.log10(1000) = 3

正確には3が返らなければなりませんが、むやみやたらと項を増やすと、浮動小数点数の丸め処理が介在してしまいますので望んでいるきれいな数字にならないことがあります。

-コード
-, , , ,

© 2021 ネーテルス