我想要一个函数来创建一个增加浮点数的数组。当增量不能精确地用二进制表示时,我会遇到问题。以0.1为增量的示例,其二进制表示形式是无限重复的。

var incrementalArray = function(start, end, step) {
    var arr = [];
    for (var i = start; i <= end; i += step) {
        // 0.1 cannot be represented precisely in binary
        // not rounding i will cause weird numbers like 0.99999999
        if (step === 0.1) {
            arr.push(i.toFixed(1));
        } else {
            arr.push(i);
        }
    }
    return arr;
};


此实现存在两个问题。 A)仅涵盖增量为0.1的情况。难道没有其他具有重复二进制表示形式的魔术数字吗? B)当增量为0.1时,返回的数组不包含结束值。但是,否则会包含最终值,否则增量将使该功能不可预测。

incrementalArray(0.0, 3.0, 0.1);
// [0.0, 0.1, 0.2, .... 2.8, 2.9]

incrementalArray(2,10,2);
// [2, 4, 6, 8, 10]


此功能如何适用于所有特殊增量并且是可预测的?

最佳答案

我认为这可能有效:

var incrementalArray = function(start, end, step) {
    var arr = [];
    // convert count to an integer to avoid rounding errors
    var count = +((end - start) / step).toFixed();
    for (var j = 0; j <= count; j++) {
        var i = start + j * step;
        arr.push(i);
    }
    return arr;
};


输出:0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1, 1.1, 1.2000000000000001, 1.3, 1.4000000000000001, 1.5, 1.6, 1.7000000000000001, 1.8, 1.9000000000000001, 2, 2.1, 2.2, 2.3000000000000002, 2.4000000000000003, 2.5, 2.6, 2.7, 2.8000000000000002, 2.9000000000000003, 3

如果要将输出截断为与输入相同的小数位数,可以使用以下命令:

var incrementalArray = function(start, end, step) {
    var prec = ("" + step).length - ("" + step).indexOf(".") - 1;
    var arr = [];
    // convert count to an integer to avoid rounding errors
    var count = +((end - start) / step).toFixed();
    for (var j = 0; j <= count; j++) {
        var i = start + +(j * step).toFixed(prec);
        arr.push(i);
    }
    return arr;
};


输出:0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0

07-24 09:15