3 คะแนน โดย GN⁺ 2023-09-28 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • คำตอบ Java humanReadableByteCount ที่เขียนในปี 2010 ถูกยืนยันในงานวิจัยปี 2018 ว่าเป็น โค้ดตัวอย่างจาก Stack Overflow ที่ถูกคัดลอกมากที่สุด แต่ให้ผลลัพธ์ผิดที่ค่าเขตแดนของการฟอร์แมตขนาดไบต์
  • โค้ดนี้อาศัยข้อเท็จจริงที่ว่าคำนำหน้าอย่าง kB, MB, GB เป็นกำลังของ 1000 หรือ 1024 และเลือกหน่วยด้วย การคำนวณลอการิทึม แทนการวนลูป
  • บั๊กหลักคือปัญหา ค่าเขตแดนจากการปัดเศษ ที่ทำให้ 999,999 bytes ถูกแสดงเป็น "1000.0 kB" ในโหมด SI ทั้งที่ตามสเปก ถ้าช่วงตัวเลขต้องอยู่ระหว่าง 1 ถึง 999.9 ผลลัพธ์ที่ถูกต้องคือ "1.0 MB"
  • สำหรับค่าที่ใหญ่กว่านั้น ยังมี ข้อจำกัดด้านความแม่นยำของเลขทศนิยมลอยตัว ของ double เข้ามาซ้อน ทำให้ค่าอินพุต 999,949,999,999,999,999 ออกมาเป็น 1000.0 PB และการแก้ต้องอาศัยการคำนวณค่าขีดแบ่ง การลดสเกล การแก้แพตเทิร์นบิต และ strictfp
  • โค้ดเวอร์ชันสุดท้ายรองรับค่าลบและ Long.MIN_VALUE ได้ แต่สูญเสียความกระชับแบบเดิมไป และการคัดลอกโค้ดจาก Stack Overflow ควรมาพร้อมกับ การทดสอบ edge case และการระบุที่มา

การทำให้เรียบง่ายที่คำตอบปี 2010 ตั้งใจไว้

  • ปัญหาคือการฟอร์แมตจำนวนไบต์ให้เป็นสตริงที่มนุษย์อ่านง่าย
    • ตัวอย่าง: แสดง 123,456,789 bytes เป็น "123.5 MB"
    • สเปกโดยนัยคือส่วนตัวเลขของสตริงผลลัพธ์ต้องอยู่ ระหว่าง 1 ถึง 999.9 และมี suffix ของขนาดที่เหมาะสมต่อท้าย
  • คำตอบก่อนหน้านี้ใช้แนวทางแบบ วนลูป โดยไล่ EB, PB, TB, GB, MB, kB, B จากหน่วยใหญ่ไปเล็ก แล้วเลือกหน่วยแรกที่มีค่าน้อยกว่าจำนวนไบต์
  • คำตอบใหม่ใช้ Math.log และ Math.pow เพื่อลดการวนลูปและการแตกแขนง
    • ในโหมด SI หน่วยคือ 1000
    • ในการเขียนแบบไบนารี หน่วยคือ 1024
    • แปลงค่า exp = log(bytes) / log(unit) เป็นจำนวนเต็มเพื่อใช้เป็นดัชนีของคำนำหน้า
    • คำนำหน้าใช้ "kMGTPE" สำหรับ SI และ "KMGTPE" สำหรับไบนารี โดยไบนารีจะเติม "i" ต่อท้าย

สภาพการคัดลอกและกรณีของ OpenJDK

  • งานวิจัยของ Sebastian Baltes Usage and Attribution of Stack Overflow Code Snippets in GitHub Projects วิเคราะห์ว่าโค้ดตัวอย่างจาก Stack Overflow ถูกนำไปใช้ในโปรเจ็กต์ GitHub อย่างไร และมีการระบุที่มาหรือไม่
  • วิธีวิเคราะห์คือดึงโค้ดตัวอย่างจาก Stack Overflow data dump แล้วนำไปเทียบกับโค้ดใน public GitHub repository
    • คำถามหลักคือมีการระบุที่มาตาม สัญญาอนุญาต CC BY-SA 3.0 ของ Stack Overflow หรือไม่
    • ผลคือผู้ใช้ส่วนใหญ่ไม่ได้ใส่การระบุที่มาที่เหมาะสม
  • คำตอบ ID 3758880 อยู่บนสุดของตารางในงานวิจัย และตอนนั้นมียอดดูหลายแสนครั้งกับอัปโหวตมากกว่า 1,000 ครั้ง
  • เมื่อค้นหา humanReadableByteCount บน GitHub จะพบการใช้งานหลายพันกรณี และใน local repository สามารถตรวจสอบได้ด้วยคำสั่งต่อไปนี้
git grep humanReadableByteCount
  • ยังพบโค้ดที่ตรงกันใน repository ของ OpenJDK ด้วย
    • โค้ดนั้นไม่มีการระบุที่มา และไลเซนส์ของ OpenJDK ก็ไม่เข้ากันกับ CC BY-SA 3.0
    • Sebastian Baltes ถามใน mailing list สำหรับนักพัฒนา OpenJDK ว่าโค้ดนี้ถูกคัดลอกจาก Stack Overflow ไปยัง OpenJDK หรือในทางกลับกัน
    • ผู้เขียนคำตอบยังไม่ได้เข้าทำงานที่ Oracle ก่อน commit นั้นจะถูกรวมเข้าไป และก็ไม่ได้มีส่วนร่วมกับแพตช์นั้น
    • หลังจากนั้นมีการเปิดอีชู และโค้ดถูกลบออก

บั๊กแรก: ค่าเขตแดนที่มี 999 ต่อเนื่องกัน

  • ปัญหาที่ดูน่าสงสัยบนผิวเผินไม่ใช่ต้นเหตุจริง
    • ค่าสูงสุดของ long คือ 2^63 - 1 หรือประมาณ 9.2 × 10^18 จึงไม่ทะลุไปเกินหน่วยหลัง EB
    • กรณี bytes < unit ถูกจัดการโดย if แรกอยู่แล้ว ดังนั้น exp จึงไม่กลายเป็น 0 จนทำให้ charAt(exp - 1) ล้มเหลว
  • ปัญหาจริงคือ ค่าเขตแดนจากการปัดเศษ
    • อินพุต 999,999 bytes กลายเป็น "1000.0 kB" ในโหมด SI
    • ตามสเปกที่กำหนดให้ส่วนตัวเลขต้องอยู่ระหว่าง 1 ถึง 999.9 ผลลัพธ์ที่ถูกต้องคือ "1.0 MB"
  • ณ เวลาที่เขียน บรรดาคำตอบที่โพสต์ไว้ทั้งหมด 22 คำตอบ รวมถึงคำตอบที่ใช้ Apache Commons และไลบรารี Android ต่างก็มีบั๊กนี้หรือรูปแบบใกล้เคียง
  • หัวใจของการแก้คือ ค่าขีดแบ่ง ที่ใช้ตัดสินว่าจะเลื่อนเลขชี้กำลัง exp ไปหน่วยถัดไปเมื่อใด
    • จุดที่เปลี่ยนจาก k เป็น M คือเมื่อค่ากลายเป็น 1 MB ที่ใกล้กว่า 999.9 k นั่นคือ 999,950
    • จุดที่เปลี่ยนจาก M เป็น G คือ 999,950,000
    • ในโหมดไบนารี ค่าขีดแบ่งไม่เป็นจำนวนเต็ม จึงต้องใช้ ceil
if (bytes >= Math.ceil(Math.pow(unit, exp) * (unit - 0.05)))
    exp++;

บั๊กที่สอง: ขีดจำกัดความแม่นยำของ double

  • แม้ใช้การแก้ข้างต้น อินพุต 999,949,999,999,999,999 ก็ยังถูกแสดงเป็น 1000.0 PB ทั้งที่ผลลัพธ์ที่ถูกต้องคือ 999.9 PB
  • สาเหตุไม่ใช่ตัวสูตรคณิตศาสตร์เอง แต่เป็น ข้อจำกัดความแม่นยำของ double
    • ในการแทนค่าแบบ IEEE 754 ค่าทศนิยมลอยตัวที่อยู่ใกล้ 0 จะถี่ แต่เมื่อค่าใหญ่ขึ้นจะห่างมาก
    • สำหรับ double ที่ใหญ่มาก แม้ลบ Long.MAX_VALUE ออกไป ค่าก็อาจไม่เปลี่ยน
double a = Double.MAX_VALUE;
double b = a - Long.MAX_VALUE;
System.err.println(a == b); // prints true
  • การคำนวณที่มีปัญหาเกิดขึ้นสองจุด
    • การหารที่ทำในอาร์กิวเมนต์ของ String.format
    • การคำนวณค่าขีดแบ่งเพื่อพิจารณาว่าจะเพิ่ม exp หรือไม่
  • ปัญหาแรกแก้โดยลดค่า bytes ระหว่างทางให้อยู่ในช่วงที่มีความแม่นยำดีกว่า แล้วปรับ exp ตาม
    • แนวคิดคือสุดท้ายผลลัพธ์ก็ต้องถูกปัดเศษอยู่แล้ว จึงยอมทิ้งหลักที่ต่ำกว่านี้ได้
if (exp > 4) {
    bytes /= unit;
    exp--;
}
  • ส่วนปัญหาที่สอง บิตล่างมีความสำคัญ
    • 999,949,99…9 และ 999,950,00…0 ต้องถูกจัดเข้าคนละเลขชี้กำลัง
    • ค่าขีดแบ่งที่เป็นไปได้มี 12 ค่าเมื่อรวม SI และไบนารี และมีเพียงค่าเดียวที่ให้ผลลัพธ์ผิด
    • ผลลัพธ์ที่ผิดสามารถระบุได้จากแพตเทิร์นบิตที่ลงท้ายด้วย D00 และจึงแก้เฉพาะกรณีนั้น
    • เนื่องจากพึ่งพาแพตเทิร์นบิตของผลลัพธ์ floating-point แบบเฉพาะ จึงต้องใส่ strictfp

อินพุตค่าลบและโค้ดสุดท้าย

  • เนื่องจาก Java ไม่มี long แบบ unsigned จึงมีการเพิ่มการรองรับจำนวนไบต์ที่เป็นลบด้วย
    • ก่อนหน้านี้ อินพุต -10,000 จะถูกแสดงเป็น -10000 B
    • มีการเพิ่ม absBytes เพื่อให้การคำนวณที่เกี่ยวกับ exp อิงจากค่าสัมบูรณ์
  • Long.MIN_VALUE ต้องมีการจัดการเป็นพิเศษ
    • เพราะ -Long.MIN_VALUE == Long.MIN_VALUE
    • ดังนั้นถ้า bytes == Long.MIN_VALUE จะใช้ Long.MAX_VALUE และในกรณีอื่นจะใช้ Math.abs(bytes)
  • เวอร์ชันสุดท้ายมีทั้ง strictfp, การแก้ค่าขีดแบ่ง, การรองรับ Long.MIN_VALUE และการลดสเกลเมื่อเลขชี้กำลังใหญ่
  • โค้ดที่เดิมตั้งใจจะหลีกเลี่ยงการวนลูปและการแตกแขนงมากเกินไป กลับกลายเป็น อ่านยากกว่าเวอร์ชันแรก หลังจากขัดเกลาทุก corner case
  • หากต้องการโค้ดเวอร์ชันล่าสุดที่พร้อมใช้งานจริง สามารถดูบทความแยก Formatting byte size to human readable format

บทเรียนที่เหลือในงานจริง

  • โค้ดตัวอย่างจาก Stack Overflow ต่อให้มีอัปโหวตหลายพันครั้งก็ อาจมีบั๊กได้
  • โค้ดที่คัดลอกมาควรได้รับการทดสอบ edge case โดยเฉพาะ
  • การคำนวณเลขทศนิยมลอยตัวจัดการได้ยากเมื่อเจอค่าเขตแดนและจำนวนที่ใหญ่มาก
  • เมื่อต้องคัดลอกโค้ด ควรมี การระบุที่มา อย่างเหมาะสม ไม่เช่นนั้นอาจกลายเป็นปัญหาจริงได้

1 ความคิดเห็น

 
GN⁺ 2023-09-28
ความคิดเห็นบน Hacker News
  • น่าสนใจที่คำตอบที่ใช้ค่าฮาร์ดโค้ดกับคำสั่ง if (หรือ while) ล้วนทำการเปรียบเทียบสูงสุด 5 ครั้ง
    ถ้าหน่วยมีแค่ B, KiB, MiB, GiB, TiB, EiB ก็แก้ได้ด้วยคำสั่ง if สูงสุด 3 ตัวเช่นกัน เพราะถ้าตรวจว่าเป็น GiB ขึ้นไป ก็จะรู้ได้ว่าไม่ใช่ B/KiB/MiB ดังนั้น binary search ชนะ
    ต่อให้ขยายไปถึง ZiB และ YiB การเปรียบเทียบสูงสุด 3 ครั้งก็ยังพอ ส่วนวิธีฮาร์ดโค้ดจะไปได้ถึงสูงสุด 7 ครั้ง ถ้าให้เขียนเอง ผมคงไม่ใช้ log/pow/เลขทศนิยมลอยตัว เพราะเสี่ยงพลาดมากเกินไป และน่าจะฮาร์ดโค้ดคำสั่ง if แต่ทำเป็น binary search

    • วิธี binary search อาจช้ากว่าการตรวจแบบง่าย ๆ 6 ครั้ง ก็ได้ แบบหลังมีแนวโน้มจะเข้ากิ่งแค่ 1 กิ่ง และการแตกกิ่งนั้นช้ามาก ดังนั้นควรทำให้โค้ดไหลเป็นเส้นตรงให้มากที่สุดเท่าที่ทำได้
    • ขึ้นอยู่กับการกระจายของอินพุต ถ้าค่าเล็ก ๆ พบได้บ่อยมาก linear search อาจดีกว่า
    • ผมมองว่านี่เป็น วิจารณญาณทางวิศวกรรม ที่แย่มาก วิธีแก้ที่เรียบง่ายทำให้เพื่อนร่วมงานตรวจทานได้ง่าย เห็นเงื่อนไขขอบเขตได้ชัด และตรวจได้ง่ายว่าเทสต์ครอบคลุมหรือไม่
      โค้ดแบบนี้เท่ากับทำงานมากมายเพื่อให้ได้โค้ดที่ช้ากว่า ซับซ้อนกว่า และทดสอบกับรีวิวได้ยากกว่า
  • (2019) การอภิปรายในอดีต:
    https://news.ycombinator.com/item?id=21693431
    https://news.ycombinator.com/item?id=21698619
    https://news.ycombinator.com/item?id=27533684

  • ไม่เข้าใจเลย ถ้ามี suffix 7 แบบ ก็เลือกอันที่ถูกด้วย binary search ได้ และใช้การเปรียบเทียบ 3 ครั้ง หรือถ้าทำแบบง่าย ๆ ก็แค่เปรียบเทียบ 6 ครั้ง
    ไม่รู้ว่าการใช้ log() สองครั้ง, pow() หนึ่งครั้ง และ ceil() ดีกว่าวิธีง่าย ๆ ตรงไหน บั๊กที่อธิบายตรงนี้เองเป็นตัวอย่างที่สมบูรณ์แบบของการพยายามฉลาดเกินไป

    • ดูเหมือนผู้เขียนจะยอมรับว่าอ่านยาก และกลับไปใช้วิธีแบบ ลูป อีกครั้ง: https://programming.guide/java/formatting-byte-size-to-human...
      ถึงอย่างนั้นก็ยังดีกว่าตัวอย่างโค้ดแรกในบทความต้นทางเล็กน้อย เพราะคำนึงถึงบั๊กการปัดเศษ
    • ผู้เขียนเองก็บอกตั้งแต่แรกว่าจริง ๆ แล้วไม่ได้ดีกว่าลูป
      อีกอย่าง การเปรียบเทียบ 6 ครั้งจะเกิดเฉพาะตอนเป็นค่าสูงสุดเท่านั้น และในการใช้งานจริงก็ดูไม่น่าจะเป็นไปได้มากนัก ถ้าค่าส่วนใหญ่อยู่ในช่วง B หรือ KB วิธีเชิงเส้นอาจดีกว่า
  • แม้จะเป็นการโปรโมตอย่างหน้าด้าน ๆ แต่ถ้าอยากฟอร์แมตขนาดให้อยู่ในรูปแบบที่มนุษย์อ่านง่ายได้อย่างรวดเร็วและถูกต้อง แทนที่จะคัดลอกจาก S/O ก็ใช้ไลบรารีโอเพนซอร์ส PrettySize ของเราได้ มีสำหรับ Rust [0] และ .NET [1] และยังช่วยให้การดำเนินการเชิงตรรกะแบบ type-safe กับขนาดไฟล์ทำได้อย่างปลอดภัยและง่ายดาย
    ชิ้นส่วนจาก S/O มี 4 บรรทัดก็จริง แต่ไลบรารีเหล่านี้ครอบคลุมกว่ามาก และมีทั้งเทสต์ ตัวเลือกฟอร์แมตเอาต์พุต การแปลงขนาด ฯลฯ
    [0]: https://github.com/neosmart/prettysize-rs
    [1]: https://github.com/neosmart/PrettySize.net

    • วัฒนธรรมที่เอาไลบรารีขนาดใหญ่โตมาแทนวิธีแก้ 4 บรรทัดนี่แหละที่ให้กำเนิด left-pad
  • สงสัยล้วน ๆ ว่า มีนักพัฒนาจำนวนไม่น้อยจริงไหมที่คัดลอกโค้ดที่ไม่น่าเชื่อถือจาก StackOverflow แล้วเอาไปวางในแอปพลิเคชันเลย?
    สมมติฐานที่ว่าผู้คนแค่คัดลอกจาก StackOverflow นั้นเป็นเรื่องที่รู้กันดี แต่ก่อนจะได้เห็นใครทำจริง ๆ ผมคิดว่ามันเป็นแค่มุกตลกมากกว่า ผมเองก็ใช้ StackOverflow เป็นจุดเริ่มต้นเวลาต้องแก้ปัญหาในพื้นที่ที่ไม่คุ้นเคย แต่ไม่เคยคัดลอกโค้ดไปตรง ๆ
    โดยปกติแล้วโค้ดชิ้นเล็ก ๆ มักไม่ได้ทำแค่สิ่งที่ผมต้องการแบบพอดีเป๊ะ จึงต้องไปดู API แล้วสร้างวิธีแก้ของตัวเองจากแนวทางที่อธิบายไว้ โดยเฉพาะใน Python StackOverflow มักช่วยชี้ทางไปยัง niche API ที่มีประโยชน์อยู่บ่อย ๆ

    • เคยทำงานกับนักพัฒนาคนหนึ่งที่พอเห็นคำตอบแล้ว ไม่มีใครห้ามไม่ให้เขาคัดลอกลงโค้ดได้เลย เขาไม่อ่านแม้แต่คำถามเพื่อดูว่าตรงกับปัญหาที่ตัวเองเจอหรือไม่ และไม่อ่านคำตอบด้วย
      พูดตามตัวอักษรคือ Google → คลิกลิงก์ Stack Overflow แรกที่เห็น → คัดลอก/วาง code block แรกที่เห็น และบางครั้งแม้แต่ภาษาก็ยังไม่ตรงกัน ระหว่าง pair programming ถึงขั้นต้องแย่งอุปกรณ์ป้อนข้อมูลออกจากมือจริง ๆ พอบอกว่ามันผิด เขาก็กำลังวางโค้ดชิ้นที่สองในหน้าเว็บนั้นแล้วก่อนจะพูดจบเสียอีก และเร็วแบบแปลก ๆ ด้วย
      แม้จะเป็นกรณีสุดโต่ง แต่ก็มีนักพัฒนาจำนวนมากที่คิดแบบ “ต้องการโค้ด; Stack Overflow มีโค้ด; จบ!” โดยไม่คิดเลยว่านั่นเป็นวิธีแก้ที่เหมาะสมหรือไม่
    • เรื่องแบบนั้นเกิดขึ้นจริง และยิ่งเป็นส่วนของโปรแกรมที่รู้สึกเหมือนอยู่นอกขอบเขตที่ผมสนใจ ก็ยิ่งเกิดบ่อยขึ้น
      ยังไงเราก็หยิบโค้ดไลบรารีที่คนแปลกหน้าเขียนมาใช้กับส่วน งานระบบท่อประปา ที่เราไม่ได้ใส่ใจมากนักอยู่ตลอด ถ้าอยากขุดลงไปทำความเข้าใจ ก็มักจะเขียนเอง แต่ถ้าส่วนนี้แค่อยากให้ “มันทำงานได้” แล้วเดินโปรเจกต์ต่อ ก็จะกลายเป็นการพัฒนาที่ขับเคลื่อนด้วยข้อผิดพลาดจากคอมไพเลอร์
    • เพราะเหตุผลที่ผู้เขียนพูดถึง ผมแทบไม่คัดลอก/วางไปตรง ๆ เลย แต่จะพยายามเข้าใจวิธีแก้แทน และถ้าจำเป็นก็ลอกด้วยมือทีละบรรทัดจนเข้าใจจริง ๆ แล้วค่อยรีแฟกเตอร์ต่อจากตรงนั้น
      ชื่อตัวแปรก็เปลี่ยนด้วย เพราะมี foo, bar, baz เยอะเกินไปจนมักอ่านยากสำหรับคน พอเจอปัญหาเดิมอีกครั้ง ก็จำได้ง่ายกว่าด้วยว่าตัวเองทำอะไรไป เมื่อเทียบกับการคัดลอกแบบหลับหูหลับตา
    • ผู้คนทำแบบนั้นจริง ๆ หลังจากเห็น โค้ดและการตั้งค่า TLS ที่ผิดจาก StackOverflow จำนวนมหาศาล ผมก็ค่อนข้างมั่นใจว่าระบบส่วนใหญ่ทำงานโดยไม่ได้ตรวจสอบใบรับรองอย่างถูกต้อง
    • คุณคงยังไม่เคยได้ลิ้มรสความสนุกของการทำงานกับ codebase ที่สร้างโดย เด็กอายุ 23 ที่กิน Adderall ล่ะมั้ง
  • ต้องการ log 2 แล้วทำไมถึงใช้ ลอการิทึมแบบ floating-point ก็ไม่รู้
    ถ้าผมไม่ได้พลาดอะไรไป นิพจน์ข้างล่างนี้ให้ค่า floor(log2(value)) ได้อย่างถูกต้องสำหรับจำนวนบวกที่น้อยกว่า 2^63 ไบต์ และเร็วกว่าเยอะ:
    Long.bitCount( (Long.highestOneBit(value) << 1) - 1) - 1

    • หน่วย “ทั่วไป” เป็น เลขยกกำลังของ 10 ดังนั้นวิธีนี้จึงไม่ถูกต้อง
  • พอเห็นโค้ดชิ้นนั้น ก็เห็นการคำนวณ log แบบ floating-point กับการหารบนจำนวนเต็มทันที เลยตัดทิ้งในหัวทันทีว่าเป็นโค้ดที่พยายามฉลาดเกินไปจนโดยเนื้อแท้แล้วมีแนวโน้มเกิดบั๊กง่าย

    • นั่นแหละโดยพื้นฐานคือประเด็นของบทความ
  • สายโซ่ของความรู้ ลงลึกไปจนสุดจริง ๆ แสดงให้เห็นว่าแม้ความรู้เล็กน้อยมาก ๆ พอเอาออกมาแล้ว จะยัดกลับเข้าไปใหม่ได้ยากแค่ไหน
    ในสถานการณ์ที่ Stack Exchange กำลังสูญเสียผู้มีส่วนร่วมที่แอคทีฟอย่างรวดเร็ว ผมสงสัยว่าต้องใช้อะไรบ้างเพื่อแก้ไข คำตอบแบบมือปืนไว ที่ภายหลังพบว่าผิดทาง และก็สงสัยด้วยว่า เมื่อคำตอบที่ “ผิดนิด ๆ” แบบนี้แข็งตัวอยู่ในประวัติการค้นหา และมากขึ้นเรื่อย ๆ ในประวัติศาสตร์ของ LLM มันจะหมายความอย่างไรต่อความรู้ร่วมของเรา

  • ทำให้นึกถึงตอนฝึกทหารขั้นพื้นฐาน ครูฝึกมักตั้งใจมอบภารกิจที่ไม่มีใครทำเป็นให้ทหารใหม่ โดยไม่ให้คำแนะนำ แล้วก็เดินจากไป
    จากนั้นจะมีใครสักคนเริ่มทำด้วยวิธีที่ผิดเสมอ และคนที่เหลือทั้งหมดก็ทำตามคนนั้น

    • สงสัยว่านิสัยของมนุษย์ที่ไม่อยากดูแย่กว่าคนอื่นทำให้เรื่องแบบนี้หนักขึ้นหรือเปล่า มันอาจนำไปสู่ผลลัพธ์โง่ ๆ ที่แม้แต่คนฉลาดก็ทำตามไอเดียแย่ ๆ หรือไอเดียที่ด่วนสรุปเกินไป
      ใน การคาดการณ์เศรษฐกิจ สาธารณะก็เกิดเรื่องคล้ายกัน คนที่ทายผิดอยู่คนเดียวขณะที่คนอื่นทายถูก จะถูกปฏิบัติอย่างรุนแรงกว่าคนที่ผิดไปพร้อมกันทุกคนมาก
    • เป้าหมายของการฝึกนั้นคืออะไร?
  • ผมไม่จำเป็นต้องมองข้อผิดพลาดแบบ floating-point ในอัลกอริทึมแบบนี้ว่าเป็น “ข้อบกพร่อง” เสมอไป ถ้าโค้ดนิยามวิธีแก้ที่ถูกต้องทั้งในเชิงตรรกะและคณิตศาสตร์ ผมก็ถือว่าตัวมันเอง “ถูก”
    การจัดการ ข้อผิดพลาดแบบ floating-point เป็นงานอีกระดับหนึ่งที่อยู่สูงขึ้นไป และทำเฉพาะเมื่อมันสำคัญจริง ๆ ผมสามารถจินตนาการถึงภาษาโปรแกรมในอนาคตที่สมบูรณ์แบบ ซึ่งไม่มีข้อผิดพลาดแบบ floating-point อยู่เลยจนไม่ต้องพิจารณา และอัลกอริทึมของผม 99% ก็เหมือนกับมุ่งเป้าไปที่ภาษานั้น