2012-04-25 12 views
11

Próbuję użyć Lapack do 128-bitowego precyzyjnego obliczenia macierzy singular value decomposition (SVD) i odkryłem, że istnieje pewna czarna magia kompilatora, aby to osiągnąć. Kompilator Intel Fortran (ifort) obsługuje opcję -r16, która nakazuje kompilatorowi przyjęcie wszystkich zmiennych zadeklarowanych jako DOUBLE PRECISION jako 128-bitowych reali. Więc skompilowany Lapack Blas przy użyciu:Używanie Lapacka z precyzją 128-bitową

ifort -O3 -r16 -c isamax.f -o isamax.o 
ifort -O3 -r16 -c sasum.f -o sasum.o 
... 

Aby włączyć to w moim programie (który jest C++) mogę użyć kompilatora Intel C++ (ICC) z opcją -Qoption,cpp,--extended_float_type który tworzy typ danych _Quad który jest 128 Zmienna zmiennoprzecinkowa. Mój przykład SVD wygląda następująco:

#include "stdio.h" 
#include "iostream" 
#include "vector" 

using namespace std; 
typedef _Quad scalar; 

//FORTRAN BINDING 
extern "C" void dgesvd_(char *JOBU, char *JOBVT, int *M, int *N, 
    scalar *A, int *LDA, 
    scalar *S, 
    scalar *U, int *LDU, 
    scalar *VT, int *LDVT, 
    scalar *WORK, int *LWORK, int *INFO); 

int main() { 
    cout << "Size of scalar: " << sizeof(scalar) << endl; 
    int N=2; 
    vector<scalar> A(N*N); 
    vector<scalar> S(N); 
    vector<scalar> U(N*N); 
    vector<scalar> VT(N*N); 

    // dummy input matrix 
    A[0] = 1.q; 
    A[1] = 2.q; 
    A[2] = 2.q; 
    A[3] = 3.q; 
    cout << "Input matrix: " << endl; 
    for(int i = 0; i < N; i++) { 
     for(int j = 0;j < N; j++) 
      cout << double(A[i*N+j]) << "\t"; 
     cout << endl; 
    } 
    cout << endl; 

    char JOBU='A'; 
    char JOBVT='A'; 
    int LWORK=-1; 
    scalar test; 
    int INFO; 

    // allocate memory 
    dgesvd_(&JOBU, &JOBVT, &N, &N, 
     &A[0], &N, 
     &S[0], 
     &U[0], &N, 
     &VT[0], &N, 
     &test, &LWORK, &INFO); 
    LWORK=test; 
    int size=int(test); 
    cout<<"Needed workspace size: "<<int(test)<<endl<<endl; 
    vector<scalar> WORK(size); 

    // run... 
    dgesvd_(&JOBU, &JOBVT, &N, &N, 
     &A[0], &N, 
     &S[0], 
     &U[0], &N, 
     &VT[0], &N, 
     &WORK[0], &LWORK, &INFO); 
    // output as doubles 
    cout << "Singular values: " << endl; 
    for(int i = 0;i < N; i++) 
     cout << double(S[i]) << endl; 
    cout << endl; 
    cout << "U: " << endl; 
    for(int i = 0;i < N; i++) { 
    for(int j = 0;j < N; j++) 
     cout << double(U[N*i+j]) << "\t"; 
    cout << endl; 
    } 
    cout << "VT: " << endl; 
    for(int i = 0;i < N; i++) { 
    for(int j = 0;j < N; j++) 
     cout << double(VT[N*i+j]) << "\t"; 
    cout << endl; 
    } 
    return 0; 
} 

skompilowany z

icc test.cpp -g -Qoption,cpp,--extended_float_type -lifcore ../lapack-3.4.0/liblapack.a ../BLAS/blas_LINUX.a 

wszystko działa prawidłowo tak daleko. Ale wyjście jest:

 
Size of scalar: 16 
Input matrix: 
1  2 
2  3 

Needed workspace size: 134 

Singular values: 
inf 
inf 

U: 
-0.525731  -0.850651 
-0.850651  0.525731 
VT: 
-0.525731  0.850651 
-0.850651  -0.525731 

Sprawdziłem, czy U i VT są poprawne, ale wartości jednostkowe oczywiście nie są. Czy ktoś ma pomysł, dlaczego tak się dzieje i jak można go obejść?
Dzięki za pomoc.

+0

Czy ten przykład działa poprawnie w przypadku zwykłej arytmetyki podwójnej precyzji? –

+0

@Zhenya Tak to robi. Oblicza prawidłowe wartości liczby pojedynczej, obliczone ze zwykłą podwójną precyzją. (4.23607, 0.236068) – Maxwell

+0

W takim przypadku sprawdziłbym procedurę 'DBDSQR': tak daleko, jak widzę ze źródła referencyjnej implementacji (http://www.netlib.org/lapack/double/dgesvd. f), oblicza wartości liczby pojedynczej z macierzami "U" i "VT". –

Odpowiedz

1

Podczas korzystania z bibliotek zewnętrznych o rozszerzonej precyzji sprawdź również, czy używają starego stylu: d1mach.f, r1mach.f, i1mach.f, aby uzyskać informacje na temat arytmetyki maszyn. W tym miejscu mogą występować pewne wartości.

To nie może być problem z Lapackiem, który używa dlamch.f (tutaj http://www.netlib.org/lapack/util/dlamch.f), który używa Fortran 90 wewnętrznych, aby uzyskać te stałe maszyny.

Ale może to być problematyczne, na przykład z BLAS lub SLATEC, jeśli ich używasz.