ฟังก์ชันกลุ่มวิศวกรรมใน Excel ดูเหมือนจะเป็นมุมที่ง่ายที่สุดในคู่มืออ้างอิงฟังก์ชัน DEC2BIN เปลี่ยนตัวเลขให้เป็นสตริงไบนารี HEX2DEC เปลี่ยนมันกลับมา IMSUM บวกตัวเลขเชิงซ้อนสองตัว แต่ละตัวดูเหมือนจะเป็นแค่แบบฝึกหัดการจัดรูปแบบ แต่ความจริงแล้วไม่ใช่ เบื้องหลังชื่อเหล่านี้คือการเข้ารหัส two's complement แบบ 10 บิต และรูปแบบตัวเลขเชิงซ้อนที่อยู่ในสตริงทั้งหมด รวมถึงตัวดำเนินการระดับบิต (bitwise operators) ที่จะล้นขอบเขต (overflow) จำนวนเต็ม 64 บิตอย่างเงียบๆ หากคุณทำการ shift ก่อนที่จะตรวจสอบ เอนจินสเปรดชีตที่เลียนแบบการทำงานของ Excel อย่างแนบเนียนจะไม่สามารถปัดเศษสิ่งเหล่านี้ทิ้งไปได้เลย
ฟังก์ชันเหล่านี้แบ่งออกเป็นสามกลุ่ม และแต่ละกลุ่มก็ซ่อนกับดักที่แตกต่างกัน การแปลงฐานเป็นเรื่องของตัวเลขติดลบและขีดจำกัดของแต่ละฐาน คณิตศาสตร์เชิงซ้อนเป็นเรื่องของการแยกวิเคราะห์ (parsing) และการจัดรูปแบบสตริง การดำเนินการระดับบิตเป็นเรื่องของการทำงานให้อยู่ในขอบเขตของ Int64 บทความนี้จะเจาะลึกไปทีละกลุ่มตามที่ HotXLS ได้นำมาใช้งาน พร้อมกับการเรียกใช้ในเวิร์กชีตที่คุณจะได้เขียนขึ้นจริงๆ
การแปลงฐานและ two's complement แบบ 10 บิต
ทิศทางไปข้างหน้าคือส่วนที่ทุกคนคาดหวัง DEC2BIN(9) จะให้ค่า "1001" และอาร์กิวเมนต์ตัวที่สองที่เป็นทางเลือกจะเติมศูนย์ด้านซ้ายของผลลัพธ์ให้มีความกว้างคงที่ กับดักก็คืออินพุตที่เป็นค่าติดลบ Excel จะไม่เขียนเครื่องหมายลบ มันจะเข้ารหัสค่าเป็นสตริง two's complement ขนาด 10 หลักในฐานเป้าหมาย ซึ่งนั่นคือเหตุผลว่าทำไม DEC2BIN(-5,10) จึงคืนค่า "1111111011" แทนที่จะมีเครื่องหมาย อาร์กิวเมนต์ตำแหน่งจะถูกละเว้นเมื่อค่าติดลบ เนื่องจากการเข้ารหัสได้ถูกตรึงไว้ที่ 10 หลักแล้ว
10 หลักคือข้อจำกัดที่ตายตัว และข้อจำกัดนั้นก็กำหนดช่วงที่สามารถแสดงผลได้ของแต่ละฐาน ในระบบไบนารี ขนาดที่จะเปลี่ยนไปเป็นซีกของค่าติดลบคือ 512 และ wrap modulus คือ 1024 ดังนั้นสตริงไบนารีจะมีเครื่องหมายก็ต่อเมื่อมีความยาว 10 ตัวอักษรพอดีและมีค่าอย่างน้อย 512 แนวคิดเดียวกันนี้ยังใช้กับขนาดของฐานต่างๆ ฐานแปด (Octal) ใช้เกณฑ์ครึ่งหนึ่งที่ 2^29 และโมดูลัสเต็มที่ 2^30 ฐานสิบหก (Hexadecimal) ใช้ 2^39 และ 2^40 ตัวอ่านของ HotXLS ใช้กฎนี้อย่างเคร่งครัด: มันจะสะสมตัวเลข และเฉพาะเมื่อสตริงมีความกว้าง 10 ตัวอักษรและค่าสะสมเท่ากับหรือมากกว่าเกณฑ์ครึ่งหนึ่งเท่านั้น มันจึงจะลบโมดูลัสเต็มรูปแบบเพื่อกู้คืนค่าที่มีเครื่องหมาย สตริงขนาด 9 ตัวอักษรจะเป็นค่าที่ไม่ติดลบเสมอ ไม่ว่ามันจะใหญ่แค่ไหนก็ตาม
ตัวเข้ารหัสคือภาพสะท้อน ค่าที่ไม่ติดลบจะถูกแปลงทีละหลักและสามารถเติมศูนย์ให้มีความกว้างตามที่ร้องขอได้ และมันจะถูกปฏิเสธหากมันเกินเพดานบวกของฐาน หรือหากความกว้างที่ร้องขอแคบเกินกว่าจะเก็บมันไว้ ค่าติดลบจะถูกนำเข้ามาอยู่ในช่วงโดยการบวกโมดูลัสเต็มรูปแบบเสียก่อน ซึ่งจะเปลี่ยนมันให้เป็นค่าที่มีการแสดงผลแบบฐานเป็น 10 หลักเสมอ จากนั้นจึงแสดงตัวเลขพร้อมกับศูนย์นำหน้าเพื่อเติมเต็มความกว้าง การตรวจสอบช่วงที่ใช้ร่วมกันเพียงหนึ่งเดียว คือขอบเขตบนและล่างที่สมมาตรกันในแต่ละฐาน เป็นสิ่งที่ทำให้ DEC2BIN, DEC2OCT และ DEC2HEX มีความสอดคล้องกันที่ขอบของมัน
นั่นทำให้เหลือแต่การแปลงข้ามฐาน เช่น HEX2BIN และ OCT2HEX ที่เปลี่ยนฐานโดยไม่ผ่านทศนิยมในชื่อฟังก์ชัน การนำไปใช้งานนั้นไม่มีรูทีนแยกต่างหากสำหรับทุกคู่ที่จัดเรียง มันจะแยกวิเคราะห์อินพุตสตริงให้เป็นค่าทศนิยมที่มีเครื่องหมายโดยใช้ฐานต้นทาง จากนั้นจัดรูปแบบค่าทศนิยมนั้นให้เป็นฐานปลายทาง ฐานสิบเป็นแกนหลัก รูทีนการแยกวิเคราะห์หนึ่งตัวและรูทีนการจัดรูปแบบหนึ่งตัว เมื่อประกอบเข้าด้วยกัน จะครอบคลุมทุกการผสมผสาน และเนื่องจากทั้งสองส่วนใช้โครงสร้าง 10 หลักที่มีเครื่องหมายเหมือนกัน ค่าที่ติดลบจึงสามารถผ่านกระบวนการนี้ได้โดยที่เครื่องหมายยังคงอยู่ครบถ้วน
ตัวเลขเชิงซ้อนคือสตริง ดังนั้นงานคือการแยกวิเคราะห์
Excel ไม่มีประเภทข้อมูลสำหรับตัวเลขเชิงซ้อน ค่าเชิงซ้อนคือสตริง "a+bi" และฟังก์ชันทุกตัวในกลุ่ม IM จะรับสตริงเหล่านี้เข้ามาและส่งกลับคืนไปหนึ่งตัว COMPLEX จะสร้างสตริงจากส่วนจริงและส่วนจินตภาพ IMSUM, IMSUB, IMPRODUCT และ IMDIV จะแยกวิเคราะห์อาร์กิวเมนต์ ทำการคำนวณในส่วนของตัวเลข และจัดรูปแบบผลลัพธ์กลับไปเป็นสตริง งานด้านตัวเลขคือพีชคณิตระดับปริญญาตรี ความยากทั้งหมดอยู่ที่การแปลงข้อความให้เป็นตัวเลขทศนิยมสองตัวอย่างน่าเชื่อถือ และนั่นคือสิ่งที่ตัวแยกวิเคราะห์ภายในทำหน้าที่ของมัน
รายละเอียดสองอย่างในตัวแยกวิเคราะห์นั้นง่ายต่อการทำผิดพลาด อย่างแรกคือหน่วยจินตภาพเดี่ยวๆ สตริง "i" หมายถึงหนึ่งคูณด้วย i ไม่ใช่ศูนย์และไม่ใช่ข้อผิดพลาด ดังนั้นเมื่อสัมประสิทธิ์หน้าคำต่อท้ายว่างเปล่าหรือเป็นเพียงเครื่องหมายบวก ตัวแยกวิเคราะห์จะต้องอ่านค่าเป็น 1 และเครื่องหมายลบเดี่ยวๆ เป็น -1 หากข้ามสิ่งนี้ไป IMSUM("i","i") ก็จะไม่เป็น 2i อีกต่อไป อย่างที่สองคือสัญกรณ์วิทยาศาสตร์ (scientific notation) ที่ชนกับเครื่องหมายที่คั่นส่วนจริงและส่วนจินตภาพ ตัวแยกวิเคราะห์จะค้นหาตัวคั่นนั้นโดยการสแกนหาเครื่องหมายบวกหรือลบ แต่ตัวเลขที่เขียนเป็น "1.5E-3" จะมีเครื่องหมายลบที่เป็นของเลขชี้กำลัง ดังนั้นการสแกนจึงปฏิเสธที่จะถือว่าเครื่องหมายบวกหรือลบเป็นตัวคั่น หากอักขระที่อยู่ก่อนหน้านั้นคือ e หรือ E หากไม่มีการป้องกันนี้ ส่วนจริงจะถูกฉีกครึ่งตรงเครื่องหมายของเลขชี้กำลัง และการแยกวิเคราะห์จะล้มเหลวทั้งที่อินพุตถูกต้องสมบูรณ์
คำต่อท้ายเองนั้นถูกเก็บรักษาไว้แทนที่จะทำให้เป็นมาตรฐาน Excel รองรับทั้ง i และ j และ HotXLS จะจำได้ว่าอินพุตใช้อะไร เพื่อให้ผลลัพธ์ที่จัดรูปแบบแล้วมีตัวอักษรเดียวกัน จากนั้นการจัดรูปแบบจะใช้ตัวย่อตามธรรมเนียม: ส่วนจินตภาพที่เป็นหนึ่งจะพิมพ์ออกมาแค่คำต่อท้าย, ลบหนึ่งพิมพ์เป็น -i, ส่วนจินตภาพที่เป็นศูนย์จะยุบรวมเหลือแค่ส่วนจริงธรรมดา, และส่วนจริงที่เป็นศูนย์จะตัด 0+ ที่นำหน้าออก
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Engineering');
// Negative input: a ten-bit two's complement, places argument ignored.
Sheet.Cells[1, 1].Value := Sheet.Calculate('=DEC2BIN(-5,10)'); // 1111111011
// Complex multiply on two "a+bi" strings.
Sheet.Cells[2, 1].Value := Sheet.Calculate('=IMPRODUCT("3+4i","1+2i")'); // -5+10i
finally
Book.Free;
end;
end;
ฟังก์ชันเชิงซ้อนอดิศัย (transcendental) ซึ่งรวมถึง IMSQRT, IMEXP, IMLN และ IMPOWER ไม่ได้ทำงานในพิกัดฉาก (rectangular coordinates) พวกมันจะแปลงค่าที่แยกวิเคราะห์แล้วให้อยู่ในรูปเชิงขั้ว (polar form) ดำเนินการกับค่าโมดูลัสและอาร์กิวเมนต์ แล้วจึงแปลงกลับ การหารากที่สองคือการแบ่งครึ่งอาร์กิวเมนต์และการหารากของโมดูลัส การยกกำลังคือการคูณอาร์กิวเมนต์และยกกำลังโมดูลัส การทำด้วยวิธีอื่นใดจะหมายถึงการหาอนุพันธ์เอกลักษณ์ใหม่ในรูปแบบมุมฉาก ซึ่งนอกจากจะใช้โค้ดมากกว่าแล้วยังมีความเสถียรเชิงตัวเลขที่น้อยกว่าเมื่ออยู่ใกล้กับจุดสาขา (branch cuts)
ตัวดำเนินการระดับบิตและ overflow ที่คุณต้องตรวจสอบก่อน
Excel 2013 ได้เพิ่ม BITAND, BITOR, BITXOR, BITLSHIFT และ BITRSHIFT อาร์กิวเมนต์เหล่านี้มีข้อจำกัด: แต่ละตัวต้องเป็นจำนวนเต็มที่ไม่ติดลบและไม่เกิน 2^48 ลบด้วย 1 และอาร์กิวเมนต์ที่เป็นเศษส่วนหรือติดลบใดๆ จะถือเป็นข้อผิดพลาดของตัวเลข เพดานนี้กว้างพอที่จะครอบคลุมชุดของธง (flag) ที่เป็นไปได้ทั้งหมด ในขณะที่ยังคงอยู่ภายในช่วงที่สามารถแสดงค่า double ได้อย่างแม่นยำ ซึ่งมีความสำคัญเพราะ Excel จะส่งมอบอาร์กิวเมนต์ตัวเลขทุกตัวในรูปแบบของค่าทศนิยม
ฟังก์ชันการ shift มีกฎการจัดเรียงหนึ่งข้อที่มักจะสร้างปัญหา การเลื่อนไปทางซ้ายสามารถสร้างค่าที่ใหญ่กว่าอินพุตได้มาก และหากคุณทำการ shl ก่อนแล้วจึงตรวจสอบผลลัพธ์ภายหลัง คุณก็ทำให้ Int64 overflow ไปแล้ว และการทดสอบนั้นก็จะไม่มีความหมาย การตรวจสอบจะต้องเกิดขึ้นก่อนการ shift HotXLS เปรียบเทียบตัวดำเนินการกับเพดานสูงสุดที่ถูกเลื่อนไปทางขวาตามจำนวนที่จะ shift และเฉพาะเมื่อตัวดำเนินการนั้นเหมาะสมเท่านั้น มันจึงจะทำการเลื่อนไปทางซ้ายจริงๆ ขนาดของการ shift ที่เกิน 53 บิตจะถูกปฏิเสธทันที และการ shift ที่ติดลบจะกลับทิศทาง ดังนั้น BITLSHIFT ด้วยจำนวนที่ติดลบจะทำหน้าที่เหมือนการเลื่อนขวา หลักการนี้สามารถประยุกต์ใช้ได้มากกว่าฟังก์ชันนี้: เมื่อมีกลไกป้องกัน overflow ป้องกันนี้จะต้องทำงานกับอินพุตเสมอ ไม่ใช่กับผลลัพธ์ที่มันตั้งใจจะปกป้อง
// Bitwise calls evaluate the same way through Calculate.
Sheet.Cells[3, 1].Value := Sheet.Calculate('=BITAND(13,11)'); // 9
Sheet.Cells[4, 1].Value := Sheet.Calculate('=BITLSHIFT(5,2)'); // 20
Sheet.Cells[5, 1].Value := Sheet.Calculate('=BITRSHIFT(40,3)'); // 5
ฟังก์ชันในอนาคตและคำนำหน้าชื่อ _xlfn
ตัวดำเนินการระดับบิตและรายการส่วนเสริมอื่นๆ ที่เพิ่มเข้ามาหลังปี 2007 มีปฏิสัมพันธ์กับรูปแบบการตั้งชื่อที่ไม่เกี่ยวข้องกับสิ่งที่พวกมันคำนวณเลย แต่เกี่ยวพันกับวิธีที่ Excel จัดเก็บพวกมันทั้งหมด รูปแบบเวิร์กชีตไบนารีดั้งเดิมได้กำหนดช่องว่างที่เป็นตัวเลขในตารางคงที่สำหรับแต่ละฟังก์ชันที่ติดตั้งมา ฟังก์ชันที่ถูกประดิษฐ์ขึ้นหลังจากตารางนั้นถูกหยุดการแก้ไขจะไม่มีช่องว่าง เพื่อที่จะบันทึกฟังก์ชันดังกล่าวลงในไฟล์และให้ Excel สมัยใหม่รู้จัก ชื่อจะถูกเขียนโดยมีคำนำหน้า _xlfn. ดังนั้น BITAND จึงถูกเก็บไว้เป็น _xlfn.BITAND บนดิสก์ แม้ว่าผู้ใช้จะพิมพ์เพียง BITAND ก็ตาม
ข้อควรระวังคือ กฎนี้ไม่ได้เป็นมาตรฐานเดียวกัน ฟังก์ชันใหม่บางตัวได้รับช่องตารางและถูกเขียนลงไปเฉยๆ ในขณะที่ฟังก์ชันที่ซ่อนอยู่เดิมบางตัวก็ถูกเขียนโดยไม่มีคำนำหน้าแม้ว่าจะเก่าแก่แค่ไหนก็ตาม HotXLS เก็บรายชื่อขาว (whitelist) อย่างชัดเจนว่าชื่อใดบ้างที่ต้องมีคำนำหน้า โดยเพิ่มคำนำหน้าในตอนที่เขียนและตัดออกเมื่ออ่าน ดังนั้นข้อความของสูตรที่คุณกำหนดและอ่านกลับมาจึงเป็นชื่อที่สะอาดและพร้อมให้ Excel ใช้งานเสมอ คุณตั้งค่า =BITLSHIFT(5,2) ไฟล์จะเก็บ _xlfn.BITLSHIFT และค่าที่ได้กลับมาจะเป็น 20 เสมอ คำนำหน้าเป็นเพียงรายละเอียดของการจัดเก็บซึ่งไม่ควรหลุดเข้าไปในสูตรที่คุณทำงานด้วยในโค้ด
นำทุกอย่างมารวมกันในเวิร์กชีต
ส่วนที่เปิดเผยสู่สาธารณะของทั้งหมดนี้มีขนาดเล็ก สร้าง TXLSXWorkbook, เพิ่มเวิร์กชีต, และเขียนสูตรลงในเซลล์ผ่าน Cells[Row, Col].Formula และคำนวณใหม่ หรือประเมินนิพจน์โดยตรงด้วยเมธอด Calculate ของเวิร์กชีต ซึ่งจะคอมไพล์สูตรเทียบกับชีตนั้นและคืนค่า Variant ตัวอย่างข้างต้นใช้ Calculate เนื่องจากมันแสดงผลลัพธ์ของการเรียกใช้งานวิศวกรรมเพียงครั้งเดียวโดยไม่มีสถานะของชีตล้อมรอบ แต่ฟังก์ชันเดียวกันนี้จะประเมินผลเหมือนกันภายในสูตรของเซลล์จริงเมื่อเวิร์กบุ๊กทำการคำนวณใหม่
การเข้ารหัสคือส่วนที่คุณควรระลึกไว้ ไม่ใช่จุดที่ใช้เรียกใช้งาน สตริงไบนารีจะมีเครื่องหมายเฉพาะเมื่อมี 10 หลักและเกินเกณฑ์ครึ่งหนึ่งสำหรับฐานของมัน ตัวเลขเชิงซ้อนคือข้อความ สัมประสิทธิ์จินตภาพที่ว่างเปล่าคือหนึ่ง และตัวแยกวิเคราะห์จะก้าวข้าม e ของเลขชี้กำลัง การเลื่อนไปทางซ้ายจะถูกตรวจสอบก่อนทำการ shift ทำให้ข้อเท็จจริงสี่ประการนี้ถูกต้องและฟังก์ชันกลุ่มวิศวกรรมจะเลิกเป็นแหล่งที่มาของความประหลาดใจจากการผิดพลาดของเครื่องหมาย
หากคุณกำลังเชื่อมโยงคณิตศาสตร์ในโดเมนของคุณเองเข้ากับเอนจินเดียวกัน กลไกของการลงทะเบียนตัวจัดการและการส่งคืนค่าได้ครอบคลุมอยู่ใน บทความของเราเกี่ยวกับการขยายเอนจินสูตรด้วยฟังก์ชันที่กำหนดเอง และเมื่อสูตรเหล่านั้นต้องเข้าถึงชีตต่างๆ ด้วยชื่อแทนที่จะเป็นที่อยู่เซลล์ คำแนะนำเกี่ยวกับชื่อที่กำหนดและสูตรข้ามชีต จะแสดงให้เห็นว่าการอ้างอิงเหล่านั้นได้รับการแก้ไขอย่างไร ฟังก์ชันวิศวกรรมที่อธิบายไว้ที่นี่ถูกรวมมาเป็นส่วนหนึ่งของ คอมโพเนนต์สเปรดชีต HotXLS สำหรับ Delphi และ C++Builder ควบคู่ไปกับ API ด้านการอ่าน, สูตร, และการจัดรูปแบบที่ได้พูดถึงที่อื่นในบล็อกนี้