@@ -157,4 +157,149 @@ alert( num.toString(2) ); // 11111111
157157
1581581. คูณและหาร
159159
160- เช่น เพื่อปัดเศษตัวเลขไปยังตําแหน่งทศนิยมที่ 2 เราสามารถคูณตัวเลขด้วย ` 100` (หรือกําลังของ 10 ที่มากกว่า) เรียกใช้ฟังก์ชันป
160+ เช่น เพื่อปัดเศษตัวเลขไปยังตําแหน่งทศนิยมที่ 2 เราสามารถคูณตัวเลขด้วย ` 100` (หรือกําลังของ 10 ที่มากกว่า) เรียกใช้ฟังก์ชันปัดเศษ แล้วหารกลับ
161+ ` ` ` js run
162+ let num = 1.23456;
163+
164+ alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23
165+ ` ` `
166+ 167+ 2. วิธี [toFixed (n)](https: // developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) ปัดเศษตัวเลขไปยัง `n` ตําแหน่งหลังจุดทศนิยมและคืนค่าเป็นสตริง
168+ 169+ ` ` ` js run
170+ let num = 12.34;
171+ alert( num.toFixed(1) ); // "12.3"
172+ ` ` `
173+ 174+ วิธีนี้ปัดขึ้นหรือลงไปยังค่าที่ใกล้ที่สุด คล้ายกับ ` Math.round` :
175+ 176+ ` ` ` js run
177+ let num = 12.36;
178+ alert( num.toFixed(1) ); // "12.4"
179+ ` ` `
180+ 181+ โปรดทราบว่าผลลัพธ์ของ ` toFixed` เป็นสตริง หากส่วนทศนิยมสั้นกว่าที่ต้องการ จะเพิ่มศูนย์ต่อท้าย:
182+ 183+ ` ` ` js run
184+ let num = 12.34;
185+ alert( num.toFixed(5) ); // "12.34000", เพิ่มศูนย์เพื่อให้ครบ 5 หลัก
186+ ` ` `
187+ 188+ เราสามารถแปลงเป็นตัวเลขโดยใช้เครื่องหมายบวกเดี่ยวหรือเรียก ` Number()` : ` +num.toFixed(5)`
189+ 190+ ## การคํานวณที่ไม่แม่นยํา
191+ 192+ ภายใน ตัวเลขถูกเก็บในรูปแบบ 64 บิต [IEEE - 754 ](https: // en.wikipedia.org/wiki/IEEE_754-2008_revision) มีบิต 64 บิตเพื่อเก็บตัวเลข: 52 บิตใช้เก็บตัวเลข, 11 บิตเก็บตําแหน่งของจุดทศนิยม (เป็นศูนย์สําหรับจํานวนเต็ม) และ 1 บิตสําหรับเครื่องหมาย
193+ 194+ ถ้าตัวเลขใหญ่เกินไป อาจล้นพื้นที่เก็บข้อมูล 64 บิต ทําให้ได้ค่าอนันต์:
195+ 196+ ` ` ` js run
197+ alert( 1e500 ); // Infinity
198+ ` ` `
199+ 200+ สิ่งที่อาจไม่ชัดเจนนัก แต่เกิดขึ้นบ่อย คือการสูญเสียความแม่นยํา
201+ 202+ พิจารณาการทดสอบนี้ (ที่ให้ผลเป็นเท็จ):
203+ 204+ ` ` ` js run
205+ alert( 0.1 + 0.2 == 0.3 ); // เท็จ
206+ ` ` `
207+ 208+ ถูกต้อง ถ้าเราตรวจสอบว่าผลรวมของ ` 0.1` และ ` 0.2` เท่ากับ ` 0.3` เราจะได้ ` เท็จ`
209+ 210+ แปลก! แล้วมันคืออะไรถ้าไม่ใช่ ` 0.3` ?
211+ 212+ ` ` ` js run
213+ alert( 0.1 + 0.2 ); // 0.30000000000000004
214+ ` ` `
215+ 216+ โอ้! มีผลกระทบมากกว่าการเปรียบเทียบที่ไม่ถูกต้อง ลองนึกภาพว่าคุณกําลังทําเว็บไซต์ขายของออนไลน์ และลูกค้าใส่สินค้ามูลค่า ` 0ドル.10` และ ` 0ドル.20` ลงในตะกร้า ยอดรวมจะเป็น ` 0ドル.30000000000000004` ซึ่งจะทําให้ทุกคนแปลกใจ
217+ 218+ แต่ทําไมถึงเกิดเรื่องนี้ขึ้น?
219+ 220+ ตัวเลขถูกเก็บในหน่วยความจําในรูปแบบไบนารี เป็นลําดับของบิต 0 และ 1 แต่เศษส่วนเช่น ` 0.1` , ` 0.2` ที่ดูง่ายในระบบเลขฐานสิบ จริงๆ แล้วเป็นเศษส่วนไม่รู้จบในระบบไบนารี
221+ 222+ กล่าวคือ ` 0.1` คืออะไร? มันคือ 1 หาร 10 หรือ ` 1/10` ในระบบเลขฐานสิบ ตัวเลขแบบนี้แสดงได้ง่าย เปรียบเทียบกับ 1 หาร 3 หรือ ` 1/3` ซึ่งเป็นเศษส่วนไม่รู้จบ ` 0.33333(3)`
223+ 224+ ดังนั้น การหารด้วยกําลังของ 10 รับประกันว่าจะทํางานได้ดีในระบบฐานสิบ แต่การหารด้วย 3 ไม่ใช่ ด้วยเหตุผลเดียวกัน ในระบบไบนารี การหารด้วยกําลังของ 2 รับประกันว่าจะทํางานได้ แต่ ` 1/10` กลายเป็นเศษส่วนไบนารีไม่รู้จบ
225+ 226+ ไม่มีทางเก็บ * 0.1 หรือ 0.2 อย่างแม่นยํา* โดยใช้ระบบไบนารี เช่นเดียวกับที่ไม่มีทางเก็บหนึ่งส่วนสามเป็นเศษส่วนทศนิยมได้อย่างแม่นยํา
227+ 228+ รูปแบบตัวเลข IEEE - 754 แก้ปัญหานี้โดยปัดเศษไปยังตัวเลขที่ใกล้ที่สุดที่เป็นไปได้ กฎการปัดเศษเหล่านี้ปกติไม่ให้เราเห็น " การสูญเสียความแม่นยําเล็กน้อย" นั้น แต่มันมีอยู่
229+ 230+ เราสามารถเห็นสิ่งนี้ในการทํางาน:
231+ ` ` ` js run
232+ alert( 0.1.toFixed(20) ); // 0.10000000000000000555
233+ ` ` `
234+ 235+ และเมื่อเรารวมสองตัวเลข " การสูญเสียความแม่นยํา" ของพวกมันจะรวมกัน
236+ 237+ นั่นคือเหตุผลที่ ` 0.1 + 0.2` ไม่เท่ากับ ` 0.3` อย่างแม่นยํา
238+ 239+ ` ` ` smart header="ไม่ใช่แค่จาวาสคริปต์"
240+ ปัญหาเดียวกันนี้มีอยู่ในภาษาโปรแกรมอื่นๆ หลายภาษา
241+
242+ PHP, Java, C, Perl, Ruby ให้ผลลัพธ์เดียวกัน เพราะพวกมันใช้รูปแบบตัวเลขเดียวกัน
243+ ` ` `
244+ 245+ เราสามารถแก้ไขปัญหานี้ได้ไหม? แน่นอน วิธีที่น่าเชื่อถือที่สุดคือปัดเศษผลลัพธ์โดยใช้วิธี [toFixed (n)](https: // developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed):
246+ 247+ ` ` ` js run
248+ let sum = 0.1 + 0.2;
249+ alert( sum.toFixed(2) ); // 0.30
250+ ` ` `
251+ 252+ โปรดทราบว่า ` toFixed` คืนค่าเป็นสตริงเสมอ มันรับประกันว่าจะมี 2 ตําแหน่งหลังจุดทศนิยม ซึ่งสะดวกถ้าเรามีร้านค้าออนไลน์และต้องแสดง ` 0ドル.30` สําหรับกรณีอื่นๆ เราสามารถใช้เครื่องหมายบวกเดี่ยวเพื่อแปลงเป็นตัวเลข:
253+ 254+ ` ` ` js run
255+ let sum = 0.1 + 0.2;
256+ alert( +sum.toFixed(2) ); // 0.3
257+ ` ` `
258+ 259+ เราสามารถคูณตัวเลขด้วย 100 (หรือตัวเลขที่ใหญ่กว่า) ชั่วคราวเพื่อเปลี่ยนให้เป็นจํานวนเต็ม ทําการคํานวณ แล้วหารกลับ เมื่อทําเช่นนี้ ข้อผิดพลาดจะลดลงบ้าง แต่ยังคงมีเมื่อหาร:
260+ 261+ ` ` ` js run
262+ alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
263+ alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
264+ ` ` `
265+ 266+ ดังนั้น วิธีคูณ/ หารช่วยลดข้อผิดพลาด แต่ไม่ได้กําจัดออกทั้งหมด
267+ 268+ บางครั้งเราอาจพยายามหลีกเลี่ยงเศษส่วนทั้งหมด เช่น ถ้าเราทําเรื่องร้านค้า เราอาจเก็บราคาเป็นเซนต์แทนดอลลาร์ แต่ถ้าเราลดราคา 30 % ล่ะ? ในทางปฏิบัติ การหลีกเลี่ยงเศษส่วนทั้งหมดแทบจะเป็นไปไม่ได้ เพียงแค่ปัดเศษตัดทศนิยมเมื่อจําเป็น
269+ 270+ ` ` ` ` smart header= " เรื่องแปลก"
271+ ลองรันโค้ดนี้ดู:
272+ 273+ ` ` ` js run
274+ // สวัสดี! ฉันเป็นตัวเลขที่เพิ่มขึ้นเอง!
275+ alert( 9999999999999999 ); // แสดง 10000000000000000
276+ ` ` `
277+ 278+ นี่เกิดจากปัญหาเดียวกัน: การสูญเสียความแม่นยํา มี 64 บิตสําหรับตัวเลข, 52 บิตใช้เก็บตัวเลข แต่ไม่พอ ดังนั้นตัวเลขที่มีนัยสําคัญน้อยที่สุดจึงหายไป
279+ 280+ จาวาสคริปต์ไม่แจ้งข้อผิดพลาดในกรณีเช่นนี้ มันพยายามทําให้ตัวเลขพอดีกับรูปแบบที่ต้องการ แต่น่าเสียดายที่รูปแบบนี้ไม่ใหญ่พอ
281+ ` ` ` `
282+ 283+ ` ` ` smart header="สองศูนย์"
284+ ผลพลอยได้ที่แปลกอีกอย่างของการแสดงตัวเลขภายในคือการมีศูนย์สองแบบ: ` 0 ` และ ` - 0 `
285+
286+ นั่นเพราะเครื่องหมายถูกแสดงด้วยบิตเดียว ดังนั้นจึงอาจตั้งค่าหรือไม่ตั้งค่าสําหรับตัวเลขใดๆ รวมถึงศูนย์
287+
288+ ในกรณีส่วนใหญ่ ความแตกต่างไม่สังเกตเห็น เพราะตัวดําเนินการปฏิบัติต่อพวกมันเหมือนกัน
289+ ` ` `
290+ 291+ ## การทดสอบ: isFinite และ isNaN
292+ 293+ จําค่าตัวเลขพิเศษสองค่านี้ได้ไหม?
294+ 295+ - ` Infinity` (และ ` -Infinity` ) เป็นค่าตัวเลขพิเศษที่มากกว่า (น้อยกว่า) ทุกอย่าง
296+ - ` NaN` แทนข้อผิดพลาด
297+ 298+ ค่าเหล่านี้เป็นประเภท ` number` แต่ไม่ใช่ตัวเลข " ปกติ" จึงมีฟังก์ชันพิเศษสําหรับตรวจสอบ:
299+ 300+ 301+ - ` isNaN(value)` แปลงอาร์กิวเมนต์เป็นตัวเลขแล้วทดสอบว่าเป็น ` NaN` :
302+ 303+ ` ` ` js run
304+ alert( isNaN(NaN) ); // จริง
305+ alert( isNaN("str") ); // จริง
0 commit comments