1

これは、使用している丸め関数です (丸め方に関するスタックオーバーフローの回答から取得されます)。半分を 2 dp に切り上げます (デフォルト)。

たとえば、2.185 は 2.19 に移動する必要があります

function myRound(num, places) {
    if (places== undefined) {
        // default to 2dp
        return  Math.round(num* 100) / 100;
    }
    var mult = Math.pow(10,places);

    return  Math.round(num* mult) / mult;
}

うまく機能しましたが、いくつかのエラーが見つかりました (Chrome と IIS 7.5 で jscript クラシック ASP として実行中の両方で)。

例えば:

alert(myRound(2.185));      // = 2.19
alert (myRound(122.185));   // = 122.19
alert (myRound(511.185));   // = 511.19
alert (myRound(522.185));   // = 522.18  FAIL!!!!
alert (myRound(625.185));   // = 625.18  FAIL!!!!

誰か知っていますか:

  1. なぜこれが起こるのか。
  2. このようなランダムな丸め誤差なしで、半分を 2 dp に丸める方法。

更新: OK、問題の核心は、js では 625.185 * 100 = 62518.499999 であり、どうすればこれを乗り越えることができるでしょうか?

4

3 に答える 3

3

あなたの問題は簡単には解決されません。これは、IEEE double がすべての 10 進数を正確に表すことができない 2 進数表現を使用するために発生します。625.185 に最も近い内部表現は 625.18499999999994543031789362430572509765625 で、これは 625.185 よりわずかに小さく、正しい丸めは下向きです。


状況に応じて、次の方法で回避できます。

Math.round(Math.round(625.185 * 1000) / 10) / 100    // evaluates to 625.19

ただし、これは厳密には正しくありません。たとえば、625.1847 が 625.19 に丸められるためです。入力の小数点以下の桁数が 3 桁を超えないことがわかっている場合にのみ使用してください。


より簡単なオプションは、丸めの前に小さなイプシロンを追加することです:

Math.round(625.185 * 100 + 1e-6) / 100

625.185 よりもわずかに小さい数値になる可能性があるため、これはまだ妥協点ですが、おそらく最初のソリューションよりも堅牢です。ただし、負の数に注意してください。

于 2013-07-03T09:45:25.837 に答える
1

値に対して toFixed 関数を使用してみてください。例は以下のとおりです。

var value = parseFloat(2.185);
var fixed = value.toFixed(2);
alert(fixed);

私は試してみましたが、うまくいきました。

編集: parseFloat(stringVar) を使用して、いつでも文字列を数値に変換できます。

EDIT2:

function myRound(num, places) {
    return parseFloat(num.toFixed(places));
}

編集3:

更新された回答、テスト済み、動作中:

function myRound(num, places) {
    if (places== undefined) {
     places = 2;
    }
    var mult = Math.pow(10,places + 1);
    var mult2 = Math.pow(10,places);
    return  Math.round(num* mult / 10) / mult2;
}

編集4:

コメントに記載されているほとんどの例でテスト済み:

function myRound(num, places) {
    if (places== undefined) {
     places = 2;
    }
    var mult = Math.pow(10,places);
    var val = num* mult;
    var intVal = parseInt(val);
    var floatVal = parseFloat(val);

    if (intVal < floatVal) {
        val += 0.1;
    }
    return Math.round(val) / mult;
}

EDIT 5: 私が見つけた唯一の解決策は、文字列を使用して正確な小数を丸めることです。ソリューションは、String プロトタイプ拡張メソッド replaceAt を使用して以下に貼り付けられます。誰かが機能していない例を見つけた場合は、確認してお知らせください。

function myRound2(num, places) {
    var retVal = null;
    if (places == undefined) {
        places = 2;
    }

    var splits = num.split('.');
    if (splits && splits.length <= 2) {
        var wholePart = splits[0];
        var decimalPart = null;
        if (splits.length > 1) {
            decimalPart = splits[1];
        }
        if (decimalPart && decimalPart.length > places) {
            var roundingDigit = parseInt(decimalPart[places]);
            var previousDigit = parseInt(decimalPart[places - 1]);
            var increment = (roundingDigit < 5) ? 0 : 1;
            previousDigit = previousDigit + increment;
            decimalPart = decimalPart.replaceAt(places - 1, previousDigit + '').substr(0, places);
        }
        retVal = parseFloat(wholePart + '.' + decimalPart);
    }

    return retVal;
}

String.prototype.replaceAt = function (index, character) {
    return this.substr(0, index) + character + this.substr(index + character.length);
}
于 2013-07-03T08:56:28.467 に答える