ในJavaScriptฉันจะได้รับ:
- จำนวนครั้งทั้งหมดที่จำนวนเต็มที่กำหนดให้เป็นอีกตัวหนึ่ง
- ที่เหลือ?
ในJavaScriptฉันจะได้รับ:
คำตอบ:
สำหรับจำนวน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. โดยวิธีการดำเนินการตามคำนิยามแบบโมดูโลแนะนำโดนัลด์ของ Knuth (เครื่องหมายตรง-หารไม่เหลือคือยุคลิดโมดูลัสหรือจาวาสคริปต์เครื่องหมายตรงเงินปันผล) เป็นสิ่งที่เราสามารถรหัสใน 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
ข้างต้นอ้างอิงจากการทดลอง 10 ล้านครั้งสำหรับแต่ละครั้ง
สรุป:ใช้(a/b>>0)
(หรือ(~~(a/b))
หรือ(a/b|0)
) เพื่อให้ได้ประสิทธิภาพเพิ่มขึ้นประมาณ 20% นอกจากนี้ยังเก็บไว้ในใจว่าพวกเขาจะไม่สอดคล้องกันทั้งหมดที่มีเมื่อMath.floor
a/b<0 && a%b!=0
Math.floor
ฟังก์ชั่น API อื่น ๆ ที่รู้~
เท่าทันหรือเรียนรู้เกี่ยวกับตัวดำเนินการ(bitwise-not) และการทำงานของ bitwise ใน JS แล้วเข้าใจถึงผลกระทบของตัวหนอนสองตัวหรือไม่
Math.floor
ดีกว่า และแม้ว่าจะไม่เป็นเช่นนี้อันนี้เป็น googleable
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 มีข้อผิดพลาดบางอย่างกับสตริงเพื่อหลีกเลี่ยงการใช้พารามิเตอร์ radix กับฐาน 10
parseInt("09", 10)
ในบางกรณีการแสดงสตริงของตัวเลขอาจเป็นสัญกรณ์ทางวิทยาศาสตร์ในกรณีนี้การแยกวิเคราะห์จะให้ผลลัพธ์ที่ไม่ถูกต้อง
parseInt(100000000000000000000000000000000, 10) // 1e+32
การโทรนี้จะสร้างผลลัพธ์ 1 รายการ
parseInt
ควรหลีกเลี่ยงเมื่อเป็นไปได้ นี่คือคำเตือนของ Douglas Crockford: "ถ้าอักขระตัวแรกของสตริงเป็น 0 สตริงจะถูกประเมินในฐาน 8 แทนฐาน 10 ในฐาน 8, 8 และ 9 ไม่ใช่ตัวเลขดังนั้น parseInt (" 08 ") และ parseInt ("09") สร้าง 0 เป็นผลลัพธ์ข้อผิดพลาดนี้ทำให้เกิดปัญหาในโปรแกรมที่แยกวันที่และเวลาโชคดีที่ parseInt สามารถรับพารามิเตอร์ radix ดังนั้น parseInt ("08", 10) จะสร้าง 8 ฉันขอแนะนำให้คุณเสมอ ระบุพารามิเตอร์ radix " archive.oreilly.com/pub/a/javascript/excerpts/…
parseInt
ควรหลีกเลี่ยง; เพียงแค่มี gotchas บางอย่างที่ต้องระวัง คุณต้องระวังสิ่งเหล่านี้และเตรียมพร้อมรับมือ
parseInt
ด้วยอาร์กิวเมนต์หมายเลข parseInt
ควรแยกสตริงที่เป็นตัวเลขบางส่วนไม่ใช่ตัดทอนหมายเลข
จาวาสคริปต์คำนวณพื้นของจำนวนลบและส่วนที่เหลือของตัวเลขที่ไม่ใช่จำนวนเต็มตามนิยามทางคณิตศาสตร์สำหรับพวกเขา
FLOOR ถูกกำหนดเป็น "จำนวนเต็มที่มากที่สุดซึ่งเล็กกว่าพารามิเตอร์" ดังนั้น:
REMAINDER ถูกกำหนดให้เป็น "ส่วนที่เหลือ" ของส่วน (Euclidean เลขคณิต) เมื่อเงินปันผลไม่ใช่จำนวนเต็มผลหารมักจะไม่ใช่จำนวนเต็มเช่นไม่มีเศษ แต่ถ้าหารหารด้วยจำนวนเต็ม (และนั่นคือสิ่งที่เกิดขึ้นเมื่อมีคนพยายามหาเศษหรือโมดูลัสของ a จำนวนจุดลอยตัว) จะมีจำนวนที่ไม่ใช่ "เหลือ" อย่างชัดเจน
JavaScript คำนวณทุกอย่างตามที่คาดไว้ดังนั้นโปรแกรมเมอร์จะต้องระมัดระวังในการถามคำถามที่เหมาะสม (และผู้คนควรระมัดระวังในการตอบคำถามที่ถาม!) คำถามแรกของ Yarin ไม่ใช่ "การหารจำนวนเต็มของ X ด้วย Y คืออะไร แต่ แทน "จำนวนครั้งทั้งหมดที่จำนวนเต็มที่กำหนดไปยังอีกรายการหนึ่ง" สำหรับตัวเลขบวกคำตอบจะเหมือนกันสำหรับทั้งคู่ แต่ไม่ใช่สำหรับจำนวนลบเนื่องจากการหารจำนวนเต็ม (การหารด้วยตัวหาร) จะน้อยกว่าจำนวนครั้งที่ตัวหาร (ตัวหาร) "-1" (การหาร) กล่าวอีกนัยหนึ่งชั้นจะคืนคำตอบที่ถูกต้องสำหรับการหารจำนวนเต็มของจำนวนลบ แต่ 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 หรือกับ FPU ของ CPU ของฉัน) สำหรับคำถามของ Yarin ซึ่งเกี่ยวข้องกับจำนวนเต็มเท่านั้นรหัสของ gammax นั้นทำงานได้อย่างสมบูรณ์
Math.floor(operation)
ส่งคืนค่าที่ปัดเศษลงของการดำเนินการ
ตัวอย่าง 1 เซนต์คำถาม:
var x = 5;
var y = 10.4;
var z = Math.floor(x + y);
console.log(z);
คอนโซล:
15
ตัวอย่าง 2 ครั้งคำถาม:
var x = 14;
var y = 5;
var z = Math.floor(x%y);
console.log(x);
คอนโซล:
4
การคำนวณจำนวนหน้าสามารถทำได้ในขั้นตอนเดียว: Math.ceil (x / y)
ความคิดเห็นของAlex Moore-Niemiเป็นคำตอบ:
สำหรับ Rubyists ที่นี่จาก Google ในการค้นหา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
) เมื่อมีการลบจำนวนที่เกี่ยวข้อง นี่เป็นกรณีสำหรับแพ็คเกจNPMdivmod
, Rubydivmod
, SWI-Prologdivmod
และการใช้งานอื่น ๆ อีกมากมายเช่นกัน
divmod
มีอยู่เนื่องจากมีการทำงานสองครั้งเร็วเท่ากับการคำนวณการดำเนินการทั้งสองแยกจากกัน การจัดให้มีฟังก์ชันดังกล่าวโดยไม่มีผลประโยชน์ด้านประสิทธิภาพนี้อาจทำให้เกิดความสับสน
หากคุณเพียงแค่หารด้วยพลังของสองคุณสามารถใช้ตัวดำเนินการระดับบิต:
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)]; }
.
คุณสามารถใช้ ternary เพื่อตัดสินใจว่าจะจัดการค่าจำนวนเต็มบวกและลบได้เช่นกัน
var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1
หากจำนวนเป็นบวกทั้งหมดจะดี ถ้าตัวเลขเป็นลบมันจะบวก 1 เพราะ Math.floor จัดการกับเนกาทีฟ
สิ่งนี้จะตัดทอนเป็นศูนย์เสมอ ไม่แน่ใจว่ามันสายเกินไปหรือไม่ แต่นี่มันจะไป:
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
};
}
หากคุณต้องการคำนวณส่วนที่เหลือสำหรับจำนวนเต็มขนาดใหญ่มากซึ่งรันไทม์ของ 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 ซึ่งตามมา ((?=...)
เป็น lookahead เชิงบวก) โดยจำนวนของอักขระที่เป็นทวีคูณของ 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 ตรวจสอบให้แน่ใจว่าได้จัดการ (แยกวิเคราะห์พื้น ฯลฯ ) ตามต้องการ