优化向上/向下取整功能

时间:2019-04-01 08:04:16

标签: javascript performance for-loop rounding

因此,我们的一位客户(拍卖师)有一组怪异的增量(也称为伦敦增量),在本质上,它们不符合任何可整的数,因此使用类似Math.round(number / increment) * increment的东西工作。

增量

From: 100, To: 299, Increment: 10
From: 300, To: 319, Increment: 20
From: 320, To: 379, Increment: 30
From: 380, To: 419, Increment: 20

这种事情还在继续。

因此,使用类似311的数字应四舍五入为320。现在,我有了这段代码,它可以正常工作,并且可以按预期对321 => 350363 => 380进行四舍五入。

我担心的是,它不是快速和/或可持续的,并且需要舍入的大量数字会变得越来越慢。显然,此功能必须与Math.round()一样快,但它不会,但要尽可能快。现在,只要我能正常工作,我的工作方式基本上就是循环X次(x是任意数字,因此我将其设置为9999999,我希望有人知道这样做的更好方法。 / p>

// Get increment amount
window.getIncrement = (num) => {
    var num = parseInt(num);
    for (var i = 0; i < window.increments.length; i++) {
        if (num >= parseInt(window.increments[i].from) && num <= parseInt(window.increments[i].to)) {
            return parseInt(window.increments[i].increment);
        }
    }
}

// Get increment start value
window.getIncrementStartValue = (num) => {
    var num = parseInt(num);
    for (var i = 0; i < window.increments.length; i++) {
        if (num >= parseInt(window.increments[i].from) && num <= parseInt(window.increments[i].to)) {
            return parseInt(window.increments[i].from);
        }
    }
};

// Custom round up function
const roundToNearestIncrement = (increment, number, roundDown) => {
    var incrementStart = parseInt(window.getIncrementStartValue(number));
    var increment = parseInt(increment), number = parseInt(number);
    console.log(incrementStart, increment, number);

    // So now we have a start value, check the direction of flow
    var lastBelow = false, firstAbove = false;
    for (var i = 0; i < 9999999; i++) {
        var incrementRounder = incrementStart + (increment * i);
        if (incrementRounder === number) { return number; }
        if (incrementRounder < number) { lastBelow = incrementRounder; }
        if (incrementRounder > number) { firstAbove = incrementRounder; }
        if (lastBelow !== false && firstAbove !== false) { break; }
        console.log('Loop #' + i + ', Below: ' + lastBelow + ', Above: ' + firstAbove);
    }
    return !roundDown ? firstAbove : lastBelow;
}

然后您像这样使用它:

// Example usage
var num = 329;
var inc = getIncrement(num);
console.log('Rounded: ' + roundToNearestIncrement(inc, num) + ', Expected: 350');

现在,正如我所说的,它可以很好地工作,但是我担心的是,如果数字使用1,234,567之类的大数字,或者仅使用该增量集的最大数字,它将减慢Node进程的速度,因为代码会循环直到找到上面和下面的数字,因此,如果有人对如何执行此操作有更好的了解,它将起作用但不会循环?

查看我之前做过的截图:

Looping code fail

您可以看到它必须循环1865次才能找到上下数量。

无论如何,您的任何想法都会受到赞赏。

3 个答案:

答案 0 :(得分:0)

有两种方法可以使速度更快

1。您可以存储一个非常大的哈希,将所有可能的值和舍入结果。这将使用很多开销,但最快。这意味着您将使用类似于

的哈希
rounded = []; rounded[0]=0 ... rounded[100] = rounded[101] = ... = rounded[109] = 110 ... and so on.

当然,此解决方案取决于表的大小。

2。基于突破点构建binary search tree,然后搜索该树。如果树是平衡的,则将以O(log(n))进行搜索。

答案 1 :(得分:0)

如果我正确理解了这个问题:

  1. 按升序预构建所有阈值的数组。我想它看起来像[0,1,2,...,320,350,380,400,420,...];
  2. 然后查找将很简单:
const findNearestThreshold = (number) => thresholdsArray
   .find(threshold => (threshold >= number));

答案 2 :(得分:0)

仅基于增量数组的解决方案。

const steps = [
   { from: 100, increment: 10}, // I don't need 'to' property here
   { from: 300, increment: 20},
   { from: 320, increment: 30},
   { from: 380, increment: 20},   
]

const roundUp = x => {
   const tooLargeIndex = steps.findIndex(({from}) => from > x);
   const { from, increment } = steps[tooLargeIndex - 1];
   const difference = x - from;
   return from + Math.ceil(difference / increment) * increment;
}

console.log(300, roundUp(300));
console.log(311, roundUp(311));
console.log(321, roundUp(321));