답변:
아니요, 보장되지 않습니다. 최적화없이 NETLIB BLAS를 사용하는 경우 결과가 동일하다는 것은 대부분 사실입니다. 그러나 BLAS 및 LAPACK의 실제 사용에는 고도로 최적화 된 병렬 BLAS를 사용합니다. 병렬화는 CPU의 벡터 레지스터 내에서 병렬로만 작동하더라도 단일 항의 평가 순서와 합산 순서도 변경되도록합니다. 이제 IEEE 표준에서 누락 된 연관 속성을 따라 결과가 동일하지 않습니다. 그래서 당신이 언급 한 것은 일어날 수 있습니다.
NETLIB BLAS에서 스칼라 곱은 인수 5에 의해 풀린 for 루프 일뿐입니다.
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 인 작은 스칼라 곱으로 나누고 합산합니다.
ATLAS, MKL, ESSL과 같은 다른 일반적인 BLAS 구현을 사용하면 각 BLAS 구현이 서로 다른 최적화를 사용하여 빠른 코드를 가져 오기 때문에이 문제는 동일하게 유지됩니다. 그러나 내가 아는 한 실제로 잘못된 결과를 초래하는 인공적인 예가 필요합니다.
BLAS 라이브러리가 동일한 결과 (비트 단위로 동일)를 리턴해야하는 경우 다음과 같은 재현 가능한 BLAS 라이브러리를 사용해야합니다.
짧은 대답
두 BLAS 구현이 동일한 순서로 작업을 수행하도록 작성되고 라이브러리가 동일한 컴파일러 플래그와 동일한 컴파일러를 사용하여 컴파일 된 경우 동일한 결과를 제공합니다. 부동 소수점 산술은 임의적 이지 않으므로 두 개의 동일한 구현은 동일한 결과를 제공합니다.
그러나 성능을 위해이 동작을 중단시킬 수있는 다양한 것들이 있습니다 ...
더 긴 대답
IEEE는 또한 각 작업의 동작 방식 외에도 이러한 작업이 수행되는 순서 를 지정 합니다. 그러나 "-ffast-math"와 같은 옵션을 사용하여 BLAS 구현을 컴파일하는 경우 컴파일러는 IEEE 부동 소수점에서는 정확한 산술에서는 정확하지만 "올바르지 않은"변환을 수행 할 수 있습니다. 정식 예제는 지적했듯이 부동 소수점 추가의 비 연관성입니다. 보다 적극적인 최적화 설정을 사용하면 연관성이 가정되며 프로세서는 작업 순서를 다시 정렬하여 최대한 많은 병렬 처리를 수행합니다.
if (x == 0) assert(x == 0)
수 있으며, 특정 관점에서는 무작위만큼 좋습니다.
if (x != 0) assert(x != 0)
확장 정밀도 산술 때문에 이어야합니다 .
일반적으로 아닙니다. 연관성을 제쳐두고 컴파일러 플래그 선택 (예 : SIMD 명령어 활성화, fused multiply add 사용 등) 또는 하드웨어 (예 : 확장 정밀도 사용 여부 )는 다른 결과를 생성 할 수 있습니다.
재현 가능한 BLAS 구현을 얻기위한 몇 가지 노력이 있습니다. 자세한 내용은 ReproBLAS 및 ExBLAS 를 참조하십시오.