javascriptで有効数字に合わせた表示をしたい

この記事はだいぶ前に書かれたものなので情報が古いかもしれません

javascriptにMath.round()みたいな関数があるんですが、これだと強制的に小数点第一位の値を四捨五入して、つまり結果が整数でしか返ってこないっぽいんですよね。

とある数字を有効数字2桁で表示したいってときには、どうやら関数で一発ってわけにはいかないようです。

んで、みんなこういうときどうしてんだろうな~って思って調べてみたんですけど、意外と誰もやってないっぽいんですよね。結構使う……かどうかはちょっと怪しいけど(俺も今回初めてだったし)、やってる人は結構いるだろって思ってたんですが、ちょい当てがはずれましたな。

「javascript 有効数字」とかでググってみたんですけど、案外参考文献が見つからない。

誰もやってる人がいないってことは、実はそれに該当する関数があるのにただ俺が知らないだけなのか、想像以上に有効数字を求めるのが難しくて誰も実現できないかのどっちかの可能性が高いんですけど、さすがに前者が調べても全く見つからないってことはないと思うので、あるとしたら後者なのか……いや、でも有効数字を求めるだけだし、それがそんな東大のエリートでないと作れないようなレベルのものだとはとても思えない。

やり方はともかく、コード作るだけなら俺程度のやつにでもできんだろ。

……と思ったので、とりあえず作ってみた。



ところで有効数字って?

まさか有効数字って言葉があまりにも世間に馴染みがないせいで調べても何も出て来ないというわけではないと思うんですが、一応念のため。

有効数字ってのは、簡単にいえばある数字の左側にある0を全部省いたあとの桁数のことです。

だから例えば有効数字2桁って言われたら、「15」とか「3.7」とかがそれに該当しますし、「0.00016」とかも有効数字が2桁ってことになります。小数点以下2桁っのとはちょっと違うのです。

「0.0000172」だったら有効数字3桁だし、「0.0000000000000000000000000000000000001」だったら有効数字は1桁です。「1」ももちろん有効数字は1桁。



というわけで

工学の世界なんかではナノレベルの話とかが出てきたりするので、すごくちっさい数を扱う場合も出てくる。例えば原子物理学の世界なんかでよく出てくるボーア半径ってやつの長さは0.00000000005291…メートルです。もしかしたら0の数が間違ってるかもしれない。工学的に書くと5.291×10-11mです。ようはすげー小さい値ってことですね。

水素原子の軌道半径がこれに該当するんだったかな……? まあ正しい知識が欲しい人はとにかくググることっすね。俺では力不足です。すまそ。

本題のjavascriptの話をしますと、このボーア半径を例のMath.round()使って四捨五入をすると、圧倒的に0になります。

alert(Math.round(0.00000000005291));

今回やりたいのは、このボーア半径の有効数字2桁を求めること。有効数字2桁ってことは、有効数字の3桁目が四捨五入されるってことなので、この場合は「0.000000000053」という答えが返ってくれば成功です。

理屈は抜きにして、とりあえず書いたソースをば。

value = 0.00000000005291;
ori_value = value;

var mod = 1;
while((ori_value / 10 >= 0) && (ori_value / 10 < 1)) {
  var mod = mod * 10;
  var ori_value = ori_value * 10;
}

//この時点でori_valueの中身は「52.91」になっている
alert(ori_value);

var new_value = value * mod;
var new_value = Math.round(new_value);
var new_value = new_value / mod;

alert(new_value);

何か回りくどいやり方をしているような気もするんですが、つまりボーア半径を、整数部分が2桁になるまで10倍し続けてるんです。

上のソースの中にもあるけど、この場合、数値は「52.91」になります。

そしたら例の四捨五入の出番です。「52.91」を四捨五入すると、小数点以下第一位の9が四捨五入されて、値は「53」になる。そしたら10倍で倍々してった分だけ、今度は割るわけです。今回だと、10倍を12回くらいしてるから、1000000000000倍くらいしたんですかね。だから元の数字に戻すためには、今度は1000000000000で割れば良いって話です。この1000000000000って値はmodという変数に入っています。



汎用的に使うには

今回は2桁だったんですけど、例えばこれが有効数字3桁を求めたかったら、whileの中身を(ori_value / 10) から(ori_value / 100)にすれば良いです。ようは求めたい桁数分を、整数部分に持ってくるってことですね。一旦整数部分に持って来て、四捨五入した後に再び小数部分にその数字を戻してやると、まあ何か微妙な言い回しですが、やっていることはそういうことです。

だからこんな感じの関数にでもしてあげればいいのかな。

function sample(value, n) {
  var grid = 1;
  for(var i = 1; i <= n; i++) {
    grid = grid * 10;
  }

  var ori_value = value;
  var mod = 1;

  while((ori_value / grid >= 0) && (ori_value / grid < 1)) {
    var mod = mod * 10;
    var ori_value = ori_value * 10;
  }

  var new_value = value * coef * mod;
  var new_value = Math.round(new_value);
  var new_value = new_value / mod;

  return new_value;
}



別に難しいことをやっているわけではないから、やっぱりもっといろんな人がやってても良いような気がするんですが、逆にたいして難しくないからわざわざ参考として載せるまでもないってことなんでしょうかね……?

まあ、もしも今回の僕と同じように有効数字を求めるプログラムをjavascriptで作らなきゃいけなくなって、どうせたいして時間はかからねーだろーけど考えるのめんどくせえから誰かソースとか公開してくれてねーかなーって思った人がついうっかり何かの間違いでこのサイトに来てしまったときにでも、役に立ったら幸いです。

通りすがり 2012年01月20日 23:45:45
NumberクラスにtoPrecisionというメソッドがあるみたいです.
まっち~ 2012年01月21日 16:59:36
あ、本当ですね。まったく知りませんでした。
何で前調べたときはそれに出会えなかったのでしょう……普通に見逃してたのかな。

何にしても、情報ありがとうございます!!
もしかしたら何か関連しているかも?