Ні, це не гарантується. Якщо ви використовуєте 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, таку як: