Greg HewgillและIllidanS4ให้ลิงก์พร้อมคำอธิบายทางคณิตศาสตร์ที่ยอดเยี่ยม ฉันจะพยายามสรุปไว้ที่นี่สำหรับคนที่ไม่ต้องการลงรายละเอียดมากเกินไป
ฟังก์ชันทางคณิตศาสตร์ใด ๆ ที่มีข้อยกเว้นบางประการสามารถแสดงด้วยผลรวมพหุนาม:
y = f(x)
สามารถว่าเปลี่ยนเป็น:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
ที่ไหน A0, A1, A2, ... มีค่าคงที่ ปัญหาคือสำหรับหลายฟังก์ชันเช่นรากที่สองสำหรับค่าที่แน่นอนผลรวมนี้มีจำนวนสมาชิกไม่สิ้นสุดมันไม่ได้จบที่x ^ nบางตัวบางตัว แต่ถ้าเราหยุดที่ค่าx ^ nเราก็ยังคงได้ผลลัพธ์ที่แม่นยำอยู่
ดังนั้นถ้าเรามี:
y = 1/sqrt(x)
ในกรณีนี้พวกเขาตัดสินใจทิ้งสมาชิกพหุนามทั้งหมดที่อยู่เหนืออันดับสองอาจเป็นเพราะความเร็วในการคำนวณ:
y = a0 + a1*x + [...discarded...]
และตอนนี้งานได้ลงมาเพื่อคำนวณ a0 และ a1 เพื่อให้ y มีความแตกต่างน้อยที่สุดจากค่าที่แน่นอน พวกเขาคำนวณแล้วว่าค่าที่เหมาะสมที่สุดคือ:
a0 = 0x5f375a86
a1 = -0.5
ดังนั้นเมื่อคุณใส่สิ่งนี้ลงในสมการคุณจะได้รับ:
y = 0x5f375a86 - 0.5*x
ซึ่งเหมือนกับบรรทัดที่คุณเห็นในโค้ด:
i = 0x5f375a86 - (i >> 1);
แก้ไข: ที่นี่จริง y = 0x5f375a86 - 0.5*x
ไม่เหมือนกับi = 0x5f375a86 - (i >> 1);
เนื่องจากการเปลี่ยน float เป็นจำนวนเต็มไม่เพียง แต่หารด้วยสอง แต่ยังหารเลขชี้กำลังด้วยสองและทำให้เกิดสิ่งประดิษฐ์อื่น ๆ แต่ก็ยังคำนวณค่าสัมประสิทธิ์บางอย่าง a0, a1, a2 ...
เมื่อมาถึงจุดนี้พวกเขาพบว่าความแม่นยำของผลลัพธ์นี้ไม่เพียงพอสำหรับวัตถุประสงค์ ดังนั้นพวกเขาจึงทำเพียงขั้นตอนเดียวของการทำซ้ำของนิวตันเพื่อปรับปรุงความแม่นยำของผลลัพธ์:
x = x * (1.5f - xhalf * x * x)
พวกเขาสามารถทำการวนซ้ำได้มากกว่านี้โดยแต่ละอันจะปรับปรุงผลลัพธ์จนกว่าจะได้ความแม่นยำที่ต้องการ นี่คือวิธีการทำงานใน CPU / FPU!แต่ดูเหมือนว่าการทำซ้ำเพียงครั้งเดียวก็เพียงพอแล้วซึ่งเป็นพรสำหรับความเร็วเช่นกัน CPU / FPU ทำการวนซ้ำได้มากเท่าที่จำเป็นเพื่อให้ได้ความแม่นยำสำหรับจำนวนทศนิยมที่เก็บผลลัพธ์และมีอัลกอริทึมทั่วไปที่ใช้ได้กับทุกกรณี
ดังนั้นในระยะสั้นสิ่งที่พวกเขาทำคือ:
ใช้ (เกือบ) อัลกอริทึมเดียวกับ CPU / FPU ใช้ประโยชน์จากการปรับปรุงเงื่อนไขเริ่มต้นสำหรับกรณีพิเศษของ 1 / sqrt (x) และอย่าคำนวณทุกอย่างเพื่อความแม่นยำของ CPU / FPU จะไป แต่หยุดก่อนหน้านี้ดังนั้น เพิ่มความเร็วในการคำนวณ