JavaScriptにおける、丸め誤差の掛け算テスト

単価:
数量:

※計算ボタンを押してみてください。
どんな結果が出てくるでしょうか?
  結果:
四捨五入:

※とてもカンタンな計算なのに、こんなになってしまいます(; ;)。
【原因】
計算機における丸め誤差が原因です。
通常の数値計算ルーチンは数値はすべて2進数扱いにするが、
2進数では10進数の小数を表現しきれないためにこういう現象がおこる。
2進数の桁は2の累乗扱いになるわけだが、小数だと、2の-1乗(つまり1/2)、
2の-2乗(1/4)という単位になる。
したがって、2のマイナス何乗かの数値の合成でうまく表現できない。
数値は無限小数になって、最後の桁を切り捨てした部分の誤差ができてしまう。


補正後 ※いったん1000倍してから積を求め、積を1000で割った後四捨五入
  結果:
四捨五入:

ソース

        function funcTesta(){
            with(document.formentry){
                tanka = parseFloat(p_tanka.value);
                suryo = parseFloat(p_suryo.value);
                p_kingaku.value = tanka * suryo;
                p_round.value = Math.round(tanka * suryo);
                tanka = tanka * 1000;
                suryo = suryo;
                p_seikai.value = tanka * suryo / 1000;
                p_seikai_round.value = Math.round(p_seikai.value);
            }
        }
        


対処方法が気になるので、いろいろ試してみました(下記参照)
java.math.BigDecimalのようなパッケージは各言語で用意されているのでしょうか??

追記:パッケージが見つかりました
BigDecimal Support for JavaScript
※上記パッケージを利用した場合

          結果:

ソース
<script type="text/javascript" src="mathcontext.js"><script>
<script type="text/javascript" src="bigdecimal.js"><script>

function funcTestDecimal(){
    with(document.formentry){
        var tanka = new BigDecimal(p_tanka.value);
        var suryo = new BigDecimal(p_suryo.value);
        var kingaku = tanka.multiply(suryo);
        p_DecKingaku.value = kingaku;
    }
}

【Cではどうなる??】
/*
 ;;;
 ;;; 小数の積がどうなるかをテスト
 ;;;
*/
#include 

main()
{
    float   f_tanka     =   158.17;
    double  d_tanka     =   158.17;
    int     suryo   =   50;
    printf("tanka(float)=%f\n",f_tanka);
    printf("tanka(double)=%f\n",d_tanka);
    printf("suryo=%d\n",suryo);
    printf("tanka * suryo(float) = %f\n",f_tanka * suryo );
    printf("tanka * suryo(double) = %f\n",d_tanka * suryo );
    exit(0);
}

結果
bash-2.02$ ./a.exe
tanka(float)=158.169998
tanka(double)=158.170000
suryo=50
tanka * suryo(float) = 7908.499908
tanka * suryo(double) = 7908.500000



【Javaではどうなるか??】 ■java.math.BigDecimalクラスを使用 import java.lang.*; import java.math.*; /** 小数の掛け算(BigDecimal) */ public class Enzan{ public static void main(String s[]) { Integer suryo = new Integer(50); Double tanka_d = new Double(158.17); BigDecimal tanka_dc = new BigDecimal("158.17"); System.out.println("Doubleの単価=>" + tanka_d.toString() ); System.out.println("Decimalの単価=>" + tanka_dc.toString() ); System.out.println("Doubleの掛け算結果=>" + (suryo.intValue() * tanka_d.doubleValue()) ); System.out.println("Decimalの掛け算結果=>" + (tanka_dc.multiply(new BigDecimal(suryo.toString())))); } } 結果 bash-2.02$ java Enzan Doubleの単価=>158.17 Decimalの単価=>158.17 Doubleの掛け算結果=>7908.499999999999 Decimalの掛け算結果=>7908.50