Answers:
对于一些数字y
和一些除数,x
将商(quotient
)和余数(remainder
)计算为:
var quotient = Math.floor(y/x);
var remainder = y % x;
floor
和%
不一致。使用trunc
而不是floor
(从而允许负的余数)或使用减法获得余数(rem = y - div * x
)。
rem
,则div
无需设下底即可更快地获得商(y - rem) / x
。2.通过Donald Knuth的推荐定义(符号匹配除数,不是余数,即欧几里德模数,也不是JavaScript符号匹配除数)的模运算,我们可以在JavaScript中编写为function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
。
我不是位运算符的专家,但是这是获取整数的另一种方法:
var num = ~~(a / b);
这同样适用于负数,而 Math.floor()
会朝错误的方向取整。
这似乎也是正确的:
var num = (a / b) >> 0;
a/b | 0
~~int
,int | 0
并且int >> 0
不会修改初始参数,而是使解释器将整数部分传递给运算符。
floor
顾名思义,几乎不会朝错误的方向走-但这并不是人们通常想要的方向!
a = 12447132275286670000; b = 128
Math.floor(a/b)
-> 97243220900677100
和~~(a/b)
-> -1231452688
。
~~(5/2) --> 2
一样(5/2)>>0 --> 2
,但是~~(5/2) + 1 --> 3
,一会儿~~(5/2)>>0 + 1 --> 1
。~~
是一个不错的选择,因为优先级更合适。
我在Firefox上做了一些速度测试。
-100/3 // -33.33..., 0.3663 millisec
Math.floor(-100/3) // -34, 0.5016 millisec
~~(-100/3) // -33, 0.3619 millisec
(-100/3>>0) // -33, 0.3632 millisec
(-100/3|0) // -33, 0.3856 millisec
(-100-(-100%3))/3 // -33, 0.3591 millisec
/* a=-100, b=3 */
a/b // -33.33..., 0.4863 millisec
Math.floor(a/b) // -34, 0.6019 millisec
~~(a/b) // -33, 0.5148 millisec
(a/b>>0) // -33, 0.5048 millisec
(a/b|0) // -33, 0.5078 millisec
(a-(a%b))/b // -33, 0.6649 millisec
以上是每个试验的1000万次试验的结果。
结论:使用(a/b>>0)
(或(~~(a/b))
或(a/b|0)
)可以使效率提高约20%。也请记住,他们与所有的不一致Math.floor
,时a/b<0 && a%b!=0
。
Math.floor
其他API函数以及谁知道多少方法,或者了解~
(按位非)运算符以及JS中的按位运算如何工作,然后了解双波浪号的作用?
Math.floor
更好地理解。即使没有,这也是可以谷歌搜索的。
ES6引入了新Math.trunc
方法。这可以修复@MarkElliot的答案,使其也适用于负数:
var div = Math.trunc(y/x);
var rem = y % x;
请注意,Math
与按位运算符相比,方法的优势在于它们可以处理2 31以上的数字。
18014398509481984 == 18014398509481985
。
~~(x/y)
。是否需要支持更大的数字(最多签名54位)?Math.trunc
如果有,请使用,Math.floor
否则使用(对负数正确)。需要支持更大的数字吗?使用一些大数字库。
divmod
,您可以将其实现为:function divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
var remainder = x % y;
return (x - remainder) / y;
Math.trunc
:) 的方法相同的值。我检查了100,3;-100,3; 100,-3和-100,-3。当然,自您发表评论以来,事情已经改变了很多时间。
我通常使用:
const quotient = (a - a % b) / b;
const remainder = a % b;
它可能不是最优雅的,但是可以工作。
您可以使用该函数parseInt
获取截断的结果。
parseInt(a/b)
要获得余数,请使用mod运算符:
a%b
parseInt对于字符串有一些陷阱,以避免使用以10为底的基数参数
parseInt("09", 10)
在某些情况下,数字的字符串表示形式可能是科学的表示法,在这种情况下,parseInt会产生错误的结果。
parseInt(100000000000000000000000000000000, 10) // 1e+32
此调用将产生1结果。
parseInt
应尽可能避免使用。这是道格拉斯·克罗克福德(Douglas Crockford)的警告:“如果字符串的第一个字符为0,则该字符串将以8为底,而不是以10为底。在8、8和9底不是数字,因此parseInt(“ 08”)和parseInt (“ 09”)的结果为0。此错误在解析日期和时间的程序中引起问题。幸运的是,parseInt可以采用基数参数,因此parseInt(“ 08”,10)可以生成8。我建议您始终提供基数参数。” archive.oreilly.com/pub/a/javascript/excerpts/...
parseInt
应该避免。只是有一些陷阱要注意。您必须意识到这些事情并做好应对的准备。
parseInt
使用数字参数调用。parseInt
应该解析部分数字的字符串,而不是截断数字。
JavaScript会根据负数的数学定义,正确计算负数的底限和非整数的余数。
FLOOR被定义为“小于参数的最大整数”,因此:
REMAINDER定义为除法(欧几里德算术)的“剩余”。当被除数不是整数时,商通常也不是整数,即没有余数,但是如果商被强制为整数(当某人尝试获取a的余数或模数时,会发生这种情况浮点数),显然会有一个非整数的“剩余”。
JavaScript确实按预期计算了所有内容,因此程序员必须谨慎地提出适当的问题(人们应该谨慎回答所提出的问题!)Yarin的第一个问题不是“ X除以Y的整数除法是什么”,但是,而是“给定整数的整数倍数”。对于正数,两个答案都相同,但是对于负数,答案并不相同,因为整数除法(除数)将比数字(除数)“乘”另一个(除数)的次数小-1。换句话说,FLOOR将为负数的整数除法返回正确答案,但是Yarin并没有要求!
gammax正确回答,该代码按照Yarin的要求工作。另一方面,塞缪尔(Samuel)是错的,我猜他没有做数学,或者他会看到它确实起作用(而且,他没有说出示例的除数,但是我希望是3):
余数= X%Y = -100%3 = -1
GoesInto =(X-余数)/ Y =(-100--1)/ 3 = -99 / 3 = -33
顺便说一句,我在Firefox 27.0.1上测试了该代码,它按预期工作,具有正数和负数以及非整数值(用于除数和除数)。例:
-100.34 / 3.57:GoesInto = -28,余数= -0.3800000000000079
是的,我注意到那里存在精度问题,但是我没有时间检查它(我不知道这是Firefox,Windows 7还是CPU的FPU出现问题)。但是对于Yarin的问题,该问题只涉及整数,gammax的代码运行完美。
Alex Moore-Niemi的回答为:
对于来自Google的Rubyists来说divmod
,您可以这样实现它:
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
结果:
// [2, 33]
divmod
使用底数除法(Math.floor
),它Math.trunc
在涉及负数时不同于截断的除法()。这是情况NPM divmod
包,红宝石divmod
,SWI-Prolog的divmod
,或许许多其他的实现了。
divmod
之所以存在,是因为它的执行速度是分别计算两个操作的两倍。在没有这种性能优势的情况下提供此类功能可能会造成混淆。
如果仅用2的幂进行除,则可以使用按位运算符:
export function divideBy2(num) {
return [num >> 1, num & 1];
}
export function divideBy4(num) {
return [num >> 2, num & 3];
}
export function divideBy8(num) {
return [num >> 3, num & 7];
}
(第一个是商,第二个是商)
function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
。
如果需要计算非常大的整数的余数,而JS运行时则不能这样表示(任何大于2 ^ 32的整数都表示为浮点数,因此会失去精度),则需要采取一些技巧。
这对于检查日常生活中许多情况下出现的许多支票号码(银行帐号,信用卡等)尤其重要。
首先,您需要将数字作为字符串(否则,您已经失去了精度,而其余部分则没有意义)。
str = '123456789123456789123456789'
现在,您需要将字符串分割成较小的部分,该部分应足够小,以便将其余部分和一段字符串串联起来可以容纳9位数字。
digits = 9 - String(divisor).length
准备一个正则表达式以分割字符串
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
例如,如果digits
为7,则regexp为
/.{1,7}(?=(.{7})+$)/g
它匹配最大长度为7的非空子字符串,其后跟((?=...)
是一个正向超前字符)后跟多个是7的倍数的字符。“ g”用于使表达式遍历所有字符串,而不是在第一次匹配时停止。
现在将每个部分转换为整数,并通过以下方式计算余数reduce
(将前一个余数-或0-乘以正确的10的幂):
reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor
这将因为“减法”余数算法而起作用:
n mod d = (n - kd) mod d
它允许将数字的十进制表示形式的任何“初始部分”用其余数替换,而不会影响最后的余数。
最终代码如下所示:
function remainder(num, div) {
const digits = 9 - String(div).length;
const splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g');
const mult = Math.pow(10, digits);
const reducer = (rem, piece) => (rem * mult + piece) % div;
return str.match(splitter).map(Number).reduce(reducer, 0);
}
3.5 % 2
求值为1.5。确保按要求处理(parseInt,floor等)