ด้วยการใช้งาน BLAS สองแบบที่แตกต่างกันเราคาดหวังได้หรือไม่ว่าพวกเขาทำการคำนวณจุดลอยตัวที่แน่นอนและกลับผลลัพธ์เดียวกัน หรือสามารถเกิดขึ้นได้เช่นหนึ่งคำนวณผลิตภัณฑ์สเกลาร์เป็น และอีกหนึ่งเป็น ( x 1 y 1 + x 2 y 2 ) + ( x 3 y 3 + x 4
ด้วยการใช้งาน BLAS สองแบบที่แตกต่างกันเราคาดหวังได้หรือไม่ว่าพวกเขาทำการคำนวณจุดลอยตัวที่แน่นอนและกลับผลลัพธ์เดียวกัน หรือสามารถเกิดขึ้นได้เช่นหนึ่งคำนวณผลิตภัณฑ์สเกลาร์เป็น และอีกหนึ่งเป็น ( x 1 y 1 + x 2 y 2 ) + ( x 3 y 3 + x 4
คำตอบ:
ไม่ว่าจะไม่รับประกัน หากคุณใช้ NETLIB BLAS โดยไม่มีการเพิ่มประสิทธิภาพใด ๆ มันเป็นเรื่องจริงที่ผลลัพธ์เหมือนกัน แต่สำหรับการใช้งานอย่างมีประสิทธิภาพของ BLAS และ LAPACK นั้นใช้ BLAS แบบขนานที่ได้รับการปรับให้เหมาะสมที่สุด การทำให้เป็นคู่ขนานนั้นจะเกิดขึ้นแม้ว่ามันจะทำงานในแบบขนานภายในเวกเตอร์ที่ลงทะเบียนของซีพียูเท่านั้นว่าลำดับของวิธีการที่คำเดียวจะถูกประเมินการเปลี่ยนแปลงและลำดับของการรวมจะเปลี่ยนแปลงเช่นกัน ตอนนี้มันจะเป็นไปตามรูปแบบของคุณสมบัติการเชื่อมโยงที่ขาดหายไปในมาตรฐาน IEEE ซึ่งผลลัพธ์จะไม่เหมือนกัน ดังนั้นสิ่งที่คุณกล่าวถึงสามารถเกิดขึ้นได้
ใน NETLIB BLAS ผลิตภัณฑ์เซนต์คิตส์และเนวิสเป็นเพียงการวนซ้ำที่ไม่ได้ควบคุมโดยปัจจัย 5:
DO I = MP1,N,5
DTEMP = DTEMP + DX(I)*DY(I) + DX(I+1)*DY(I+1) +
$ DX(I+2)*DY(I+2) + DX(I+3)*DY(I+3) + DX(I+4)*DY(I+4)
END DO
และมันก็ขึ้นอยู่กับคอมไพเลอร์ถ้าการเพิ่มการคูณแต่ละครั้งลงใน DTEMP ทันทีหรือถ้าส่วนประกอบทั้งหมด 5 ตัวถูกรวมกันก่อนแล้วจึงเพิ่มเข้าไปใน DTEMP ใน OpenBLAS มันขึ้นอยู่กับสถาปัตยกรรมเคอร์เนลที่ซับซ้อนมากขึ้น:
__asm__ __volatile__
(
"vxorpd %%ymm4, %%ymm4, %%ymm4 \n\t"
"vxorpd %%ymm5, %%ymm5, %%ymm5 \n\t"
"vxorpd %%ymm6, %%ymm6, %%ymm6 \n\t"
"vxorpd %%ymm7, %%ymm7, %%ymm7 \n\t"
".align 16 \n\t"
"1: \n\t"
"vmovups (%2,%0,8), %%ymm12 \n\t" // 2 * x
"vmovups 32(%2,%0,8), %%ymm13 \n\t" // 2 * x
"vmovups 64(%2,%0,8), %%ymm14 \n\t" // 2 * x
"vmovups 96(%2,%0,8), %%ymm15 \n\t" // 2 * x
"vmulpd (%3,%0,8), %%ymm12, %%ymm12 \n\t" // 2 * y
"vmulpd 32(%3,%0,8), %%ymm13, %%ymm13 \n\t" // 2 * y
"vmulpd 64(%3,%0,8), %%ymm14, %%ymm14 \n\t" // 2 * y
"vmulpd 96(%3,%0,8), %%ymm15, %%ymm15 \n\t" // 2 * y
"vaddpd %%ymm4 , %%ymm12, %%ymm4 \n\t" // 2 * y
"vaddpd %%ymm5 , %%ymm13, %%ymm5 \n\t" // 2 * y
"vaddpd %%ymm6 , %%ymm14, %%ymm6 \n\t" // 2 * y
"vaddpd %%ymm7 , %%ymm15, %%ymm7 \n\t" // 2 * y
"addq $16 , %0 \n\t"
"subq $16 , %1 \n\t"
"jnz 1b \n\t"
...
ซึ่งแยกผลิตภัณฑ์สเกลาร์ออกเป็นผลิตภัณฑ์สเกลาร์ขนาดเล็กที่มีความยาว 4 และรวมเข้าด้วยกัน
การใช้การใช้งาน BLAS ทั่วไปอื่น ๆ เช่น ATLAS, MKL, ESSL, ... ปัญหานี้ยังคงเหมือนเดิมเพราะการใช้งาน BLAS แต่ละครั้งจะใช้การปรับแต่งที่แตกต่างกันเพื่อรับโค้ดที่รวดเร็ว แต่เท่าที่ฉันรู้จำเป็นต้องมีตัวอย่างเทียมเพื่อให้ได้ผลลัพธ์ที่ผิดพลาดจริงๆ
หากจำเป็นต้องให้ไลบรารี BLAS ส่งคืนผลลัพธ์เดียวกัน (บิตที่ชาญฉลาดเหมือนกัน) จะต้องใช้ไลบรารี BLAS ที่ทำซ้ำได้เช่น:
คำตอบสั้น ๆ
หากการประยุกต์ใช้ BLAS ทั้งสองนั้นถูกเขียนขึ้นเพื่อดำเนินการตามลำดับเดียวกันและไลบรารีถูกคอมไพล์โดยใช้คอมไพเลอร์แฟล็กเดียวกันและคอมไพเลอร์เดียวกันพวกเขาจะให้ผลลัพธ์เดียวกัน การคำนวณเลขทศนิยมไม่ได้สุ่มดังนั้นการใช้งานสองแบบที่เหมือนกันจะให้ผลลัพธ์ที่เหมือนกัน
อย่างไรก็ตามมีหลายสิ่งที่สามารถทำลายพฤติกรรมนี้เพื่อประสิทธิภาพ ...
คำตอบอีกต่อไป
IEEE ยังระบุลำดับที่การดำเนินการเหล่านี้ดำเนินการนอกเหนือไปจากการดำเนินการแต่ละอย่าง อย่างไรก็ตามหากคุณรวบรวมการใช้ BLAS ด้วยตัวเลือกเช่น "-ffast-math" คอมไพเลอร์สามารถทำการแปลงที่จะเป็นจริงในเลขคณิตที่แน่นอน แต่ไม่ "ถูกต้อง" ใน IEEE ตัวอย่างที่ยอมรับได้คือการไม่เชื่อมโยงของการเพิ่มจุดลอยตามที่คุณชี้ให้เห็น ด้วยการตั้งค่าการเพิ่มประสิทธิภาพที่ก้าวร้าวมากขึ้นการเชื่อมโยงจะถูกสันนิษฐานและโปรเซสเซอร์จะทำสิ่งนั้นมากในแบบขนานเท่าที่จะทำได้โดยการสั่งซื้อการดำเนินการอีกครั้ง
if (x == 0) assert(x == 0)
อาจล้มเหลวซึ่งจากมุมมองที่แน่นอนจะดีเท่าการสุ่ม
if (x != 0) assert(x != 0)
เพราะเลขคณิตที่มีความแม่นยำเพิ่มขึ้น
โดยทั่วไปไม่มี การทิ้งความสัมพันธ์ไว้ข้างกันตัวเลือกของธงคอมไพเลอร์ (ตัวอย่างเช่นคำสั่ง SIMD ถูกเปิดใช้งานการใช้การเพิ่มแบบทวีคูณผสมฯลฯ ) หรือฮาร์ดแวร์ (เช่นการใช้ความแม่นยำแบบขยาย ) อาจให้ผลลัพธ์ที่แตกต่างกัน
มีความพยายามบางอย่างในการรับการประยุกต์ใช้ BLAS ที่ทำซ้ำได้ ดูReproBLASและExBLASสำหรับข้อมูลเพิ่มเติม