แปลงเลขฐาน

พิมพ์ตัวเลขแล้วเห็นผลเป็นฐานสอง ฐานแปด ฐานสิบ และฐานสิบหกพร้อมกัน รวมถึงฐานอื่นตั้งแต่ 2 ถึง 36 ทุกอย่างคำนวณด้วยเลขจำนวนเต็มแบบแม่นยำ ค่าขนาด 64 บิตจึงเก็บครบทุกหลัก ลองเอา FFFFFFFFFFFFFFFF ไปวางในเว็บแปลงส่วนใหญ่จะได้ 18446744073709552000 ซึ่งไม่ใช่ตัวเลขนั้นและไม่มีอะไรเตือน ส่วนทศนิยมแปลงทีละหลักแทนการใช้เลขทศนิยมของเครื่อง 0.1 ฐานสิบจึงไปถึงฐานสามได้ครบ และถ้าเศษส่วนวนซ้ำไม่รู้จบ ระบบจะบอก ไม่ใช่ปัดทิ้งเงียบ ๆ

แต่ละฐานใช้ที่ไหน และทำไมต้องเป็นฐานนั้น

สี่ฐานครอบคลุมเกือบทั้งหมดที่เจอในชีวิตจริง และแต่ละฐานถูกใช้ด้วยเหตุผลที่จับต้องได้ ไม่ใช่เพราะความเคยชิน

ฐานตัวเลขเจอที่ไหนทำไมฐานนี้
2 ฐานสอง 0 1 บิตสิทธิ์การเข้าถึง รีจิสเตอร์ฮาร์ดแวร์ bitmask ค่า prefix ของเครือข่าย สายไฟมีแค่ติดกับดับ ฐานอื่นทั้งหมดเป็นแค่ตัวย่อของฐานนี้
8 ฐานแปด 0 ถึง 7 chmod 755 และแทบไม่มีที่อื่นแล้ว สามบิตต่อหนึ่งหลัก ซึ่งพอดีกับชุดอ่าน เขียน และรัน ฐานแปดยังอยู่ในที่ที่ของมาเป็นชุดละสาม
16 ฐานสิบหก 0 ถึง 9 และ A ถึง F รหัสสี ที่อยู่หน่วยความจำ ค่าแฮช การดัมพ์ไบต์ รหัส Unicode สี่บิตต่อหนึ่งหลัก จึงเป็นสองหลักต่อหนึ่งไบต์พอดีเสมอ ไม่มีวันที่หนึ่งไบต์กว้างเป็นครึ่งตัวอักษร
10 ฐานสิบ 0 ถึง 9 ที่เหลือทั้งหมด เพราะคนมีสิบนิ้ว ไม่มีเหตุผลที่ดีกว่านี้ และไม่เคยมี

ฐานที่สูงกว่านั้นมีไว้เพื่อความกระชับ ฐาน 36 ใช้ตัวเลขทุกตัวและตัวอักษรทุกตัว จึงเป็นฐานที่หนาแน่นที่สุดที่เขียนด้วยแป้นพิมพ์ธรรมดาได้โดยไม่ต้องแยกตัวพิมพ์เล็กใหญ่ และเป็นเหตุผลที่รหัสย่อลิงก์และเลขที่คำสั่งซื้อบางเจ้าใช้ฐาน 36 ส่วนฐาน 32 กับฐาน 58 ไปไกลกว่านั้นด้วยการตัดตัวอักษรที่คนพิมพ์ผิดบ่อยทิ้ง ฐาน 58 ที่ใช้กับที่อยู่บิตคอยน์ไม่มี 0, O, I และ l เลย ด้วยเหตุผลว่าที่อยู่ที่อ่านให้ฟังทางโทรศัพท์ควรรอดถึงปลายทาง

คำนำหน้า

ตัวเลขที่เขียนไว้มักบอกฐานของตัวเองอยู่แล้ว 0x คือฐานสิบหก 0b คือฐานสอง และ 0o คือฐานแปด ในภาษาโปรแกรมเกือบทุกภาษาที่เขียนหลังภาษาซี ส่วนเลขศูนย์นำหน้าเปล่า ๆ เคยหมายถึงฐานแปดในภาษาซีรุ่นเก่าและในเชลล์บางตัว ซึ่งเคยทำให้เกิดบั๊กจริง รหัสไปรษณีย์หรือเวลาที่เขียนว่า 08 ถูกอ่านเป็นฐานแปดแล้วถูกปฏิเสธ เพราะ 8 ไม่ใช่ตัวเลขในฐานแปด หน้านี้อ่านคำนำหน้าแบบสมัยใหม่ได้ และจะบอกเมื่อคำนำหน้าขัดกับฐานที่คุณเลือก แทนที่จะเดาเอาเองว่าใครถูก

เลขฐานสองที่จริง ๆ แล้วเป็นข้อความ ไม่ใช่ตัวเลข

อันนี้คือความเข้าใจผิดที่ควรรู้ไว้ เพราะไม่มีอะไรเตือนคุณตอนที่ทำผิด

ชุดของเลขหนึ่งกับศูนย์เป็นได้สองอย่างที่ต่างกันสิ้นเชิง

  • ตัวเลขที่เขียนในฐานสอง 1001000 คือเจ็ดสิบสอง นี่คือสิ่งที่หน้านี้มีไว้ทำ
  • ข้อความที่ถูกเข้ารหัสเป็นไบต์ 01001000 01101001 ชุดเดียวกันนี้คือคำว่า Hi เขียนเป็นสองกลุ่ม กลุ่มละแปดบิต

ถ้าเอาแบบที่สองมาวางในเครื่องแปลงเลขฐาน คุณจะได้คำตอบ เป็นคำตอบจริงของคำถามจริง และไม่ใช่คำถามที่คุณถาม มันจะให้ 18537 มาแทน Hi โดยไม่บ่นอะไรเลย เพราะข้อมูลที่ใส่เข้าไปเป็นเลขฐานสองที่ถูกต้องสมบูรณ์อยู่แล้ว

จุดสังเกตคือการจัดกลุ่มและความยาว ข้อความจะเขียนเป็นกลุ่มละแปด หรือเป็นชุดยาวติดกันที่ความยาวหารด้วยแปดลงตัว ส่วนตัวเลขจะเขียนตามที่มันออกมา ความยาวไม่แน่นอน และมักไม่มีศูนย์นำหน้า ถ้าเลขหนึ่งกับศูนย์ของคุณมาจากเกมปริศนา เกม หรือใบงาน โอกาสที่มันเป็นข้อความสูงกว่าเป็นตัวเลขมาก

กรณีนั้นให้ใช้หน้า รหัสลับคลาสสิก ซึ่งมีตัวแปลงฐานสองที่ทำงานกับข้อความและอ่านไบต์เป็น UTF-8 ภาษาไทยและอีโมจิจึงรอดครบทั้งไปและกลับ หน้านั้นยังรองรับสิ่งอื่นที่โผล่มาในปริศนาชุดเดียวกันด้วย ทั้ง A1Z26 ที่แทนตัวอักษรด้วยลำดับในชุดตัวอักษร และการเลื่อนแบบ Caesar, Atbash และ Vigenère

แล้วค่อยกลับมาหน้านี้เมื่อสิ่งที่คุณมีเป็นตัวเลขจริง ๆ ซึ่งได้แก่บิตสิทธิ์การเข้าถึง ค่าในรีจิสเตอร์ รหัสสี และ network mask

ทำไมต้องคำนวณแบบไม่ปัดเศษ และอะไรพังถ้าไม่ทำ

เครื่องแปลงเลขฐานบนเว็บส่วนใหญ่ใช้ชนิดตัวเลขของภาษาตัวเอง ซึ่งใน JavaScript คือทศนิยมลอยตัว 64 บิต มันเก็บจำนวนเต็มได้ตรงเป๊ะถึง 253 หรือ 9,007,199,254,740,992 พ้นจากนั้นจะเริ่มปัดไปหาค่าที่มันเขียนได้

ผลที่ตามมาดูออกง่ายและมองข้ามง่ายพอ ๆ กัน

ใส่เข้าไป ฐานสิบหกฐานสิบที่ถูกต้องที่ทศนิยมลอยตัวให้
FFFFFFFFFFFFFFFF 18,446,744,073,709,551,615 18,446,744,073,709,552,000
1FFFFFFFFFFFFF 9,007,199,254,740,991 9,007,199,254,740,991 ยังตรงอยู่ เพราะนี่คือเส้นแบ่งพอดี

แถวแรกคือค่า 64 บิตที่ทุกบิตเป็นหนึ่ง ซึ่งเป็นเลขใหญ่ที่คนแปลงบ่อยที่สุด ไม่ว่าจะเป็นค่าสูงสุดของจำนวนเต็มไม่มีเครื่องหมาย bitmask เต็มชุด หรือตำแหน่งในไฟล์ คำตอบจากทศนิยมลอยตัวผิดที่สี่หลักสุดท้ายและไม่มีคำเตือนใด ๆ เลย ส่วนหลังนี่แหละที่สำคัญ คำตอบผิดที่ประกาศตัวเองคือความไม่สะดวก แต่คำตอบผิดที่ดูเหมือนถูกคือบั๊กที่หลุดขึ้น production หน้านี้ใช้การคำนวณจำนวนเต็มแบบไม่ปัดเศษและไม่มีเพดานบน ตัวเลขที่คุณได้จึงคือตัวเลขที่มันเป็นจริง ๆ

ส่วนที่เป็นเศษ

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

คำถามที่พบบ่อย

ตัวเลขของฉันถูกส่งไปไหนไหม

ไม่ การแปลงเกิดขึ้นในแท็บนี้ขณะที่คุณพิมพ์ นโยบายความปลอดภัยของเว็บกำหนด connect-src ‘none’ เบราว์เซอร์จึงบล็อกการเรียกเครือข่ายจากหน้านี้ ต่อให้โค้ดอยากส่งออกไปก็ส่งไม่ได้

มี parseInt อยู่แล้ว ทำไมต้องมีหน้านี้

เพราะ parseInt เลิกให้คำตอบที่ถูกตั้งแต่ประมาณเก้าพันล้านล้าน และไม่บอกด้วย ลองสั่งให้แปลง FFFFFFFFFFFFFFFF มันจะคืน 18446744073709552000 ทั้งที่คำตอบคือ 18446744073709551615 ต่างกัน 385 มาแบบเงียบ ๆ ในกรณีที่คนแปลงเลขฐานสิบหกเจอบ่อยที่สุด ทุกอย่างในหน้านี้ใช้จำนวนเต็มความละเอียดไม่จำกัด จึงไม่มีขนาดไหนที่มันเริ่มเดา

ทำไม 0.1 ในฐานสองถึงไม่ลงตัว

ด้วยเหตุผลเดียวกับที่หนึ่งส่วนสามไม่ลงตัวในฐานสิบ คือฐานนั้นไม่มีวิธีเขียนมันได้พอดี หนึ่งส่วนสิบในฐานสองคือ 0.0001100110011 วนไปเรื่อย ๆ ซึ่งก็เป็นเหตุผลที่ 0.1 บวก 0.2 ในภาษาโปรแกรมส่วนใหญ่ได้ 0.30000000000000004 หน้านี้จะบอกคุณเมื่อเศษส่วนวนซ้ำ แทนที่จะปัดทิ้งแล้วปล่อยให้เข้าใจว่ามันลงตัว

บรรทัดที่บอกค่าแบบมีเครื่องหมายคืออะไร

บิตชุดเดียวกันมีความหมายได้สองแบบ ขึ้นกับว่าโปรแกรมที่สร้างมันถือว่าบิตบนสุดเป็นเครื่องหมายหรือไม่ 0xFFFFFFFF คือ 4,294,967,295 ถ้าอ่านแบบไม่มีเครื่องหมาย และเป็น -1 ถ้าอ่านแบบมีเครื่องหมาย ตัวไหนถูกขึ้นกับโปรแกรมที่เขียนมันล้วน ๆ เราจึงแสดงทั้งสองแบบ เพราะข้อมูลดิบที่คุณกำลังดูไม่ได้บอกว่าเป็นแบบไหน

วาง 0x, 0b หรือเว้นวรรคได้ไหม

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

ทำไมฐานหยุดที่ 36

เพราะมีตัวเลข 10 ตัวกับตัวอักษร 26 ตัว รวมได้ 36 พอดี เกินจากนั้นไม่มีข้อตกลงว่าสัญลักษณ์ถัดไปควรเป็นอะไร ส่วน Base64 มีอยู่จริงแต่เป็นคนละเรื่อง มันเข้ารหัสไบต์ ไม่ได้เขียนตัวเลข ซึ่งเป็นหน้าที่ของเครื่องมือ Base64 บนเว็บนี้