在JavaScript中,我如何获得:
给定整数进入另一个整数的整数倍?
剩下的?
JavaScript根据数学定义计算负数的底限和非整数的其余部分 .
FLOOR定义为“小于参数的最大整数”,因此:
正数:FLOOR(X)= X的整数部分;
负数:FLOOR(X)= X的整数部分减1(因为它必须比参数小,即更负!)
REMAINDER被定义为除法的“遗留”(欧几里德算术) . 当被除数不是整数时,商通常也不是整数,即没有余数,但如果商被强制为整数(当有人试图获得余数或模数时会发生这种情况)浮点数),显然会有一个非整数“遗留” .
JavaScript确实按预期计算了所有内容,因此程序员必须小心提出正确的问题(人们应该小心回答问题!)Yarin的第一个问题不是“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,Remainder = -0.3800000000000079
是的,我注意到,那里存在精确问题,但我没有时间检查它(我不知道它是Firefox,Windows 7还是我的CPU的FPU的问题) . 但是,对于Yarin的问题,只涉及整数,gammax的代码完美无缺 .
Alex Moore-Niemi的评论作为答案:
对于来自Google的Rubyists来搜索 divmod ,你可以这样实现它:
divmod
function divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
结果:
// [2, 33]
我在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万次试验 .
Conclusion: 使用 (a/b>>0) (或 (~~(a/b)) 或 (a/b|0) )可实现约20%的效率提升 . 还要记住,当 a/b<0 && a%b!=0 时,它们都与 Math.floor 不一致 .
(a/b>>0)
(~~(a/b))
(a/b|0)
a/b<0 && a%b!=0
Math.floor
计算页数可以一步完成:Math.ceil(x / y)
这将始终截断为零 . 不确定是否为时已晚,但在这里:
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 }; }
您也可以使用三元来决定如何处理正整数值和负整数值 .
var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1
如果数字是正数,一切都很好 . 如果数字为负数,则会因为Math.floor处理负数而添加1 .
您可以使用函数 parseInt 来获取截断的结果 .
parseInt
parseInt(a/b)
要获得余数,请使用mod运算符:
a%b
parseInt有一些字符串的缺陷,以避免使用基数为10的radix参数
parseInt("09", 10)
在某些情况下,数字的字符串表示形式可以是科学记数法,在这种情况下,parseInt将产生错误的结果 .
parseInt(100000000000000000000000000000000, 10) // 1e+32
此调用将生成1作为结果 .
我通常使用 (a - a % b) / b . 它可能不是最优雅的,但它确实有效 .
(a - a % b) / b
对于某些数字 y 和一些除数 x 计算商( quotient )和余数( remainder )如下:
y
x
quotient
remainder
var quotient = Math.floor(y/x); var remainder = y % x;
Math.floor(operation) 返回操作的向下舍入值 .
Math.floor(operation)
第一个问题的例子:
var x = 5; var y = 10.4; var z = Math.floor(x + y); console.log(z);
安慰:
15
第二个问题的例子:
var x = 14; var y = 5; var z = Math.floor(x%y); console.log(x);
4
ES6引入了新的Math.trunc方法 . 这允许修复@MarkElliot's answer以使其也适用于负数:
var div = Math.trunc(y/x); var rem = y % x;
请注意, Math 方法优于按位运算符,它们使用的数字超过231 .
Math
我不是按位运算符的专家,但这是获得整数的另一种方法:
var num = ~~(a / b);
这对于负数也适用,而 Math.floor() 将在错误的方向上循环 .
Math.floor()
这似乎也是正确的:
var num = (a / b) >> 0;
如果你只是用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]; }
(第一个是商,第二个是余数)
var remainder = x % y; return (x - remainder) / y;
如果需要计算非常大的整数的余数,那就是JS运行时不能表示为(任何大于2 ^ 32的整数表示为浮点数,因此它会失去精度),你需要做一些技巧 .
这对于检查许多我们日常生活中存在的校验位数(银行帐号,信用卡......)尤为重要 .
首先,你需要你的数字作为一个字符串(否则你已经失去了精度,其余的没有意义) .
str = '123456789123456789123456789'
您现在需要将字符串拆分成较小的部分,足够小,以便任何余数和一段字符串的串联可以适合9位数 .
digits = 9 - String(divisor).length
准备正则表达式以拆分字符串
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
例如,如果 digits 为7,则正则表达式为
digits
/.{1,7}(?=(.{7})+$)/g
它匹配一个最大长度为7的非空子串,后面跟着( (?=...) 是一个正向前瞻)由多个7的字符组成.'g'用于使表达式遍历所有字符串,而不是在第一次匹配时停止 .
(?=...)
现在将每个部分转换为整数,并按 reduce 计算余数(加回前一个余数 - 或0 - 乘以10的正确幂):
reduce
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); }
15 回答
JavaScript根据数学定义计算负数的底限和非整数的其余部分 .
FLOOR定义为“小于参数的最大整数”,因此:
正数:FLOOR(X)= X的整数部分;
负数:FLOOR(X)= X的整数部分减1(因为它必须比参数小,即更负!)
REMAINDER被定义为除法的“遗留”(欧几里德算术) . 当被除数不是整数时,商通常也不是整数,即没有余数,但如果商被强制为整数(当有人试图获得余数或模数时会发生这种情况)浮点数),显然会有一个非整数“遗留” .
JavaScript确实按预期计算了所有内容,因此程序员必须小心提出正确的问题(人们应该小心回答问题!)Yarin的第一个问题不是“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,Remainder = -0.3800000000000079
是的,我注意到,那里存在精确问题,但我没有时间检查它(我不知道它是Firefox,Windows 7还是我的CPU的FPU的问题) . 但是,对于Yarin的问题,只涉及整数,gammax的代码完美无缺 .
Alex Moore-Niemi的评论作为答案:
对于来自Google的Rubyists来搜索
divmod
,你可以这样实现它:结果:
我在Firefox上做了一些速度测试 .
以上是基于每个1000万次试验 .
Conclusion: 使用
(a/b>>0)
(或(~~(a/b))
或(a/b|0)
)可实现约20%的效率提升 . 还要记住,当a/b<0 && a%b!=0
时,它们都与Math.floor
不一致 .计算页数可以一步完成:Math.ceil(x / y)
这将始终截断为零 . 不确定是否为时已晚,但在这里:
您也可以使用三元来决定如何处理正整数值和负整数值 .
如果数字是正数,一切都很好 . 如果数字为负数,则会因为Math.floor处理负数而添加1 .
您可以使用函数
parseInt
来获取截断的结果 .要获得余数,请使用mod运算符:
parseInt有一些字符串的缺陷,以避免使用基数为10的radix参数
在某些情况下,数字的字符串表示形式可以是科学记数法,在这种情况下,parseInt将产生错误的结果 .
此调用将生成1作为结果 .
我通常使用
(a - a % b) / b
. 它可能不是最优雅的,但它确实有效 .对于某些数字
y
和一些除数x
计算商(quotient
)和余数(remainder
)如下:Math.floor(operation)
返回操作的向下舍入值 .第一个问题的例子:
安慰:
第二个问题的例子:
安慰:
ES6引入了新的Math.trunc方法 . 这允许修复@MarkElliot's answer以使其也适用于负数:
请注意,
Math
方法优于按位运算符,它们使用的数字超过231 .我不是按位运算符的专家,但这是获得整数的另一种方法:
这对于负数也适用,而
Math.floor()
将在错误的方向上循环 .这似乎也是正确的:
如果你只是用2的幂除法,你可以使用按位运算符:
(第一个是商,第二个是余数)
如果需要计算非常大的整数的余数,那就是JS运行时不能表示为(任何大于2 ^ 32的整数表示为浮点数,因此它会失去精度),你需要做一些技巧 .
这对于检查许多我们日常生活中存在的校验位数(银行帐号,信用卡......)尤为重要 .
首先,你需要你的数字作为一个字符串(否则你已经失去了精度,其余的没有意义) .
您现在需要将字符串拆分成较小的部分,足够小,以便任何余数和一段字符串的串联可以适合9位数 .
准备正则表达式以拆分字符串
例如,如果
digits
为7,则正则表达式为它匹配一个最大长度为7的非空子串,后面跟着(
(?=...)
是一个正向前瞻)由多个7的字符组成.'g'用于使表达式遍历所有字符串,而不是在第一次匹配时停止 .现在将每个部分转换为整数,并按
reduce
计算余数(加回前一个余数 - 或0 - 乘以10的正确幂):这将因“减法”余数算法而起作用:
允许用数字的余数替换数字的十进制表示的任何“初始部分”,而不影响最终的余数 .
最终的代码如下: