ときたの技術ノート

アウトプット!!!近道はない。泥臭く頑張れ。

文字列と数値の演算が異なる理由

やりたかったこと・やったこと

・文字列の数値同士で引き算がしたかった
文字列→数値型に変換して引き算を行った

1の補数を取得するプログラム*1

function oneComplement(bits){
    let n = bits.length;
    let oneComplement = "";
    for(let i=0; i < n; i++) {
        oneComplement+="1";
    }
    console.log(oneComplement);
    let one = String(Number(oneComplement) - bits);
    console.log(one);

    return one.length == n ? one : one.padStart(n, '0');

}

入力値

"0011000101000000111101011111100001001011000001011010101001010110110101101001000101011010011010011100100100000101110"

結果

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1.100111010111111e+114*2

→桁数が大きすぎて計算ができていない。 →数値の引き算で期待する結果が得られなかった。

原因

端的にいえば、文字列と数値ではデータ型が異なるため、というのが理由。

コンピュータは数値を2進数で表現するが、有限のビット数しか使えないため*3数値の精度に制限があるということを抑えておきたい。特に、浮動小数点数の場合、小数点以下の桁数が制限されるため、計算結果が正確に表現されないことがあるとのこと。これが、数値の引き算で期待する結果が得られない場合がある理由。

今回でいえば、入力値の桁数が数値として扱える有限ビット数の桁数をオーバーしていたのが原因。

*1:アンチパターン

*2:末尾がe+114となる数値は、科学的表記法(指数表記法)と呼ばれます。e+114は、10の114乗を表しています。つまり、上記の数値は1.100111010111111 × 10の114乗を表しています。

*3:コンピュータが扱えるビット数は、アーキテクチャやプロセッサによって異なるが、一般的には8ビット、16ビット、32ビット、または64ビットがよく使われる。ビット数が大きいほど、より大きな範囲の数値を表現することができますが、同時にメモリや計算速度の要件も増える。