在javascript中,我如何获得:
一个给定整数进入另一个整数的整数?
剩下的?
对于某个数y和某个除数x计算商(quotient和余数(remainder为:
1 2
| var quotient = Math.floor(y/x);
var remainder = y % x; |
- %在javascript中处理浮动(这与许多其他语言不同),这可能是不需要的:3.5 % 2的计算结果为1.5。确保按要求处理(ParseInt、Floor等)
- 数学中-4.5的整数部分是-5,因为-5是"可能的最高整数,但仍然低于-4.5"。
- 然而,无论您决定对负数做什么,它都应该在商和余数之间保持一致。使用EDOCX1、1和EDCX1〔2〕在一起是不一致的。要么使用EDCOX1,3,而不是EDCOX1,1,(从而允许负余数),或者使用减法来获得余数(EDOCX1,5)。
- Math.floor()的用法仅在给定数为正的情况下使用。请看这一点,以作更多解释。通常EDCOX1×7是更好地选择整数或数字的一部分。
- 1。如果你想计算剩余的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); }。
- @马克里德,图基:考虑到问题的描述,我不明白2怎么可能进入-9总共-5次。你能解释一下吗?
- -9/2=-4.5。然后你走-4.5层,也就是-5层。记住-5小于-4.5,楼层操作定义为小于给定值的最大整数。
- 请注意,通常情况下,-3模5是2而不是-3可能令人惊讶,但在数学上更有用,因为它避免了0附近的任何不连续性;任何整数模a正n总是在[0,n-1]范围内,无论起始整数是正的还是负的。但要符合这个定义并保持身份正确,商必须是下限。
- @关于三种模(和整数除法)的详细信息,请参阅维基百科。
- 注意,这不适用于负数,因为-9 % 2是-1,而不是1。
我不是位运算符方面的专家,但这里有另一种获得整数的方法:
这也适用于负数,而Math.floor()将向错误的方向进位。
这似乎也是正确的:
- 另一个目的,我刚刚花了20分钟想弄清楚的,显然是a/b | 0。
- @user113716@blueraja位操作只有在整数类型上才有意义,JS(当然)知道这一点。~~int、int | 0和int >> 0不修改初始参数,而是使解释器将不可分割的部分传递给运算符。
- 以防有人想知道哪一个速度最快:jspef.com/integer-division-math-floor-a-b-vs-a-b(spoiler结果看起来不确定)。
- 鉴于它的名字,floor几乎不会朝着错误的方向转弯——只是它不是人们通常想要的方向而已!
- 那是一个布谷布谷。a = 12447132275286670000; b = 128Math.floor(a/b)->97243220900677100和~~(a/b)->-1231452688。
- 注意优先顺序。~~(5/2) --> 2和(5/2)>>0 --> 2一样,但~~(5/2) + 1 --> 3和~~(5/2)>>0 + 1 --> 1一样。~~是一个很好的选择,因为优先级更合适。
- emscripten和asm.js使用|0的原因是>>0的不必要行为。
- 只是澄清一下,这些实际上是有效的,因为它们不是操作,所有JS位操作都转换为32位整数。
- 同意乔尼·利兹。事实上,虽然这个解决方案值得一提,但我会拒绝它作为最佳编码实践。Mark Elliot的答案使用为此目的提供的函数。这个答案依赖于一种行为,这种行为既不是由位操作的实现所保证,也不是由其预期的。
- 答案是buubuus~~(2147483648/1)=-2147483648(2147483648/1)>>0=-2147483648
- 在没有数学库的情况下很好(在我的例子中,在模板中)
- 这个答案适用于符合有符号整数范围的数字,因为JavaScript只使用最低有效32位进行位运算。但是在大多数语言中,关于整数运算和整数的操作实际上是32位有符号数(JS实际上没有整数),所以我认为这不是问题。是的,对于很大的数字,它会失败,但是当数字超过53位时,Math.floor也会失败…这只是所有地方都存在的固有局限性。如果您想对任意大的数字执行此操作,则需要一些bigint/bignumber库。
- 我不会说Math.floor向错误的方向舍入负商,而是向不同的方向舍入。然后,Math.floor(-3 / 10) === -1对应于楼层划分(向下取整),而~~(-3 / 10) === 0对应于截断划分(向零取整)。参见wiki:modulo操作。
- 这本质上是代码混淆。不要为了聪明而这样做,使用稍长但可读性更强的Math.floor或es6(edge 12+)的新Math.trunc
- @bfred.it大多数开发人员已经接受使用| 0来截短,特别是由于它在asm.js中的使用,所以您不能确切地说它混淆了代码,因为它的含义已经被广泛了解。
- 我是在评论答案,但没有提到|0。另外,asm.js使用一种特定的风格也无关紧要,因为它不是由人类编写/读取,而是由蒸腾者和浏览器编写/读取。
- 它是IDK。你第一次看到三元看起来很奇怪。空条件一开始看起来也很奇怪。没有人说不要使用它们,因为它们看起来很聪明;相反,它们是开发人员希望学习的新语言补充。如果EDOCX1 8或EDCOX1 6的引用不存在,可能有人试图添加它们。正如乔尔所说,"旧密码不生锈"。不要因为旧的习惯而使用有用的现有约定。这是一个不错的选择。
- 在Buu Bu这个词中是否有我不知道的开发环境?我想我们不是在谈论龙珠Z技能还是儿童服装线?
- 说真的不要这样做。这是一个不可读的黑客。
我在Firefox上做了一些速度测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| -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万个试验为每个。
结论:使用EDCX1〔5〕(或EDCOX1×6)或EDCOX1〔7〕,可获得约20%的增益。同时,当EDCX1为9时,它们都与EDCX1〔8〕不一致。
- 我发现math.floor()的性能比其他人更稳定。上下都比较少
- 下面是一组很好的测试用例:jspef.com/whole-integer-division
- 请注意,只有在经常做的情况下,为速度优化整数除法才有意义。在任何其他情况下,我建议选择最简单的一个(无论你和你的同事觉得哪个最简单)。
- @M01完全同意-在网上关注这样的东西太多了
- "M01",但更难:学习EDCOX1(0)和谁知道有多少其他API函数,或学习关于EDCOX1×1(位不)操作符和位操作如何在JS中工作,然后理解双倾斜的效果?
- 如果你的同事没有在汇编程序中编程,他们可能会更好地理解EDCOX1 0。即使不是,这也是GooGabelabl。
- 0:2582.521MS~~:2631.94MS Ma.Lead:382.893MS。我鼓励您自己运行测试,PLNKR.CO/EDIT/9G0IXJPAVR2T2D2L1DC0。
- @我来这里是为了找Javascript中的整数除法,这不是一个利基需求。
- @Markgreen是的,但是仅仅想这样做并不意味着你应该以一种奇怪的形式来写它,因为它恰好是最快的,没有很好的理由——代码的清晰性通常应该是你的首要考虑。而且,在语言更改之后,以及在不同的浏览器之间,这些测试可能完全没有意义——您需要进行分析,以找出应用程序中的慢问题,不管怎样。它不太可能是你的整数除法,除非你已经优化过其他任何事情!
ES6引入了新的Math.trunc方法。这样可以修正@markelliot的答案,使其也适用于负数:
1 2
| var div = Math.trunc(y/x);
var rem = y % x; |
注意,与位运算符相比,Math方法的优点在于,它们使用的数字超过231。
- var y=1801439850948184;var x=5;div=?-臭虫?
- @4esn0k这不是一个bug。您的数字太多,在64位二进制格式的IEEE754数字中不能有那么高的精度。例如,18014398509481984 == 18014398509481985。
- 18014398509481984==2**54,我特别使用这个数字,因为它是以二进制64格式精确表示的。答案也被准确地表达出来了。
- @我解释得不太好。我是说18014398509481984 / 5是3602879701896396.8。但是,它不能被存储,所以它被转换为3602879701896397。然后,Math.trunc(3602879701896397)就是3602879701896397。
- 好吧,我花了一整天的时间思考如何解决这个问题。似乎可以确定是否存在舍入和更正"截断商":如果(y/x==div&;&;rem>x-rem)div-=1;",但我不确定是否正确,不管怎样,您的解决方案对大多数情况都足够好。
- 我认为选择很简单:您需要支持最多32位带符号的数字?使用~~(x/y)。需要支持更大的数字,最多54位有符号?如果有,请使用Math.trunc,否则使用Math.floor(负数正确)。需要支持更大的数字吗?使用一些大数字图书馆。
- 对于google上搜索divmod的红人来说,可以这样实现:function divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
1 2
| var remainder = x % y;
return (x - remainder) / y; |
- 不幸的是,当x=-100时,这个版本没有通过测试,因为它返回-34而不是-33。
- "var x=0.3;var y=0.01;"怎么样?(感谢github.com/julialang/julia/issues/4156 issuecomment-23324163‌&8203;)
- 实际上,@samuel,使用负值,这个方法返回正确的结果,或者至少返回与使用Math.trunc的方法相同的值。我查了100,3;-100,3;100,-3和-100,-3。当然,自从你的评论和事情改变之后,很多时间都过去了。
您可以使用函数parseInt获得截断的结果。
要获取余数,请使用mod operator:
parseint有一些字符串的缺陷,以避免使用基数为10的基数参数。
在某些情况下,数字的字符串表示可以是一个科学的符号,在这种情况下,parseint将产生错误的结果。
1
| parseInt(100000000000000000000000000000000, 10) // 1e+32 |
此调用将产生1。
- 尽可能避免使用parseInt。这是道格拉斯·克罗克福德的警告:"如果字符串的第一个字符是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根据负数的数学定义,正确计算负数和非整数的余数。
楼层定义为"小于参数的最大整数",因此:
- 正数:楼层(X)=X的整数部分;
- 负数:floor(x)=x减去1的整数部分(因为它必须小于参数,即更负!)
余数被定义为除法(欧几里得算法)的"余数"。当被除数不是整数时,商通常也不是整数,也就是说,没有余数,但是如果商被强制为整数(这就是当有人试图得到一个浮点数的余数或模时所发生的情况),显然会有一个非整数"剩余"。
javascript确实按预期计算了所有的东西,所以程序员必须小心地提出正确的问题(人们应该小心地回答被问到的问题!)雅林的第一个问题不是"x除以y的整数是什么",而是"一个给定整数进入另一个整数的整数"。对于正数,两者的答案是相同的,但对于负数则不同,因为整数除法(除数除以除数)将比一个数(除数)"进入另一个数(除数)"的时间小-1。换句话说,floor将返回一个负数整数除法的正确答案,但是yarin没有问这个问题!
Gammax回答正确,代码按Yarin的要求工作。另一方面,塞缪尔是错的,他没有做数学,我猜,或者他会看到它是有效的(另外,他没有说他的例子的除数是多少,但我希望是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、Windows7或我的CPU的FPU的问题)。但是对于Yarin的问题,它只涉及整数,gammax的代码工作得很好。
Math.floor(operation)返回操作的舍入值。
第一个问题示例:
1 2 3 4 5
| var x = 5;
var y = 10.4;
var z = Math.floor(x + y);
console.log(z); |
慰问:
15
第二个问题的例子:
1 2 3 4 5
| var x = 14;
var y = 5;
var z = Math.floor(x%y);
console.log(x); |
慰问:
4
亚历克斯·摩尔·尼米的评论作为答案:
对于google搜索divmod中的ruby用户,您可以这样实现它:
1 2 3 4 5
| function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
} |
结果:
- 通常情况下,当涉及负数时,使用浮动划分(EDOCX1&1),这与松散划分(EDOCX1&2)不同。这是NPM divmod的实例,Ruby divmod,Swi-Prolog divmod和许多其他实例。
- Truncated division gives more naturally looking results than floored division,but compatibility trumps that,IMO.Maybe,there are mathematical or performance reasons for using floored division,too.注意到通常情况下,divmodExists because it's performs twice as fast as computing the two operations separately.提供这样一种功能,而没有这种性能的好处可能会被混淆。
我通常使用:
1 2
| const quotient = (a - a % b) / b;
const remainder = a % b; |
它可能不是最优雅的,但它很管用。
- 很好的解决方案,因为它避免了分析或截断浮点的丑陋。
- 如果你需要两个商和一个再生商,计算再生商的先决条件,然后再确定再生商在表示商数中的价值,I.E.Quoote=(A-remainder)/B;
计算页数可以一步完成:数学,CEL(X/Y)
如果只使用两个幂除,则可以使用位运算符:
1 2 3 4 5 6 7 8 9 10 11
| 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];
} |
(第一个是商,第二个是余数)
如果需要计算非常大的整数的余数,而JS运行时不能这样表示(任何大于2^32的整数都表示为浮点,因此会失去精度),则需要执行一些技巧。
这对于检查日常生活中的许多情况(银行帐号、信用卡等)中出现的许多支票数字的情况尤其重要。
首先,您需要将数字作为一个字符串(否则,您已经失去了精度,其余部分就没有意义)。
1
| str = '123456789123456789123456789' |
现在,您需要将字符串拆分为更小的部分,足够小,以便任何余数和一段字符串的连接可以容纳9位数字。
1
| digits = 9 - String(divisor).length |
准备正则表达式以拆分字符串
1
| splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g') |
例如,如果digits为7,则regexp为
它匹配一个最大长度为7的非空子字符串,该子字符串的后面((?=...)是一个正的lookahead),是7的倍数。"g"是使表达式在所有字符串中运行,而不是在第一次匹配时停止。
现在,将每个部分转换为整数,并用reduce计算余数(加上前一个余数-或0-乘以正确的10次方):
1
| reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor |
这将工作,因为"减法"余数算法:
1
| n mod d = (n - kd) mod d |
它允许用余数代替数字的小数表示的任何"初始部分",而不影响最终余数。
最后的代码看起来像:
1 2 3 4 5 6 7 8
| 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);
} |
这将始终截断为零。不确定是不是太迟了,但接下来是:
1 2 3 4 5 6 7 8 9 10
| function intdiv(dividend, divisor) {
divisor = divisor - divisor % 1;
if (divisor == 0) throw new Error("division by zero");
dividend = dividend - dividend % 1;
var rem = dividend % divisor;
return {
remainder: rem,
quotient: (dividend - rem) / divisor
};
} |
您可以使用三元来决定如何处理正整数值和负整数值。
1
| var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1 |
如果数字是正数,一切都好。如果数字是负数,那么它将加1,因为math.floor处理负数的方式。