我正在学习函数式编程。在本练习中,我想创建一个自然溢出的函数。例如,如果数据的范围是2-12,如果输入的值是12并且你加1,它就变成2.同样,如果你从2中减去1,它就变成了12。需要注意的是,我想提高自己的数学技能,因为在过去的15年里,我并没有像数学家一样思考。如果这看起来相当微不足道,请原谅我。
第一个实现如下:
var confineRange(value, min, max) {
var newValue = value;
while (newValue > max) {
newValue -= max;
}
while (newValue < min) {
newValue = max - (min - newValue);
}
return newValue;
}
这种实现有效,但是看到一个循环,意味着它可以改进。所以我尝试的第二个版本是:
function confineRange(value, min, max) {
if (value > 0)
return (value % max - min)
if (value < 0)
return ((value + max) % max) - min
if (value == 0)
return max - min;
}
但是,这个版本看起来可以简化得更多。
答案 0 :(得分:1)
首先为简单起见,假设max
&gt;符合min
关系,且value
大于或等于min
:
function confineRange(value, min, max) {
return ((value - min) % (max - min + 1)) + min;
}
您的范围的下端是min
,您希望将其限制在max - min + 1
范围内。例如,使用min = 2
和max = 12
的示例,结果可以获得11个不同的值! (而不是像它看起来那样的第一个)。
让我们用边缘情况进行测试:
confineRange(2, 2, 12);
这将执行((2 - 2) % (12 - 2 + 1)) + 2
,结果为2,良好。
confineRange(12, 2, 12);
这将执行((12 - 2) % (12 - 2 + 1)) + 2
,结果为12,也很好。请注意,12 - 2
生成10,这是将通过% 11
未修改的最大整数。现在让我们试试13:
confineRange(13, 2, 12);
现在在部分计算之后,它看起来像(11 % 11) + 2
,它将按预期生成2(即如果13达到12 + 1,则它似乎正确地回绕到2)。
所以基本的想法就是这个。
然而,由于Javascript可能会或可能不会处理负数,该函数可能会因数字低于2而失败,例如,请参阅this article。我不知道行为是标准化的还是特定的浏览器可能会或者可能不会尝试修复它,所以最好假设这个未定义。
现在的问题是你不可能在'%'运算符中输入负数,但是在这个界面中你只能用'%'(模数)解决问题。所以必须采用其他方法。
JavaScript具有Math.floor()
函数,该函数始终向下舍入(check it here)。使用它可以消除负面问题,所以让我们从中构造我们自己的模数:
function confineRange(value, min, max) {
t = value - min;
d = max - min + 1;
t = t - (Math.floor(t / d) * d);
return t + min;
}
模数发生在第三行(t = t - (Math.floor(t / d) * d);
)行,这会独立于符号计算t % d
。此解决方案也适用于2以下的数字,因此如果您将{1}作为value
提供示例,则您将获得12。
对于你的第二个问题,这个问题可以通过位操作解决,但只有当范围(你想得到的不同值的数量)是2的幂时。这种情况应用一个正确的AND(&
)值上的掩码将完成这项工作。