Использование Lapack с точностью 128 бит

Я пытаюсь использовать Lapack для вычисления 128-битной точности матрицы разложение по единичным значениям (SVD), и я обнаружил, что для этого существует некая черная магия компилятора. Компилятор Intel Fortran (ifort) поддерживает параметр -r16, который указывает компилятору, что все переменные, объявленные как DOUBLE PRECISION, должны быть 128-битными вещественными числами. Итак, я скомпилировал Lapack и BLAS, используя:

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

Чтобы включить это в мою программу (которая написана на C++), я могу использовать компилятор Intel C++ (icc) с параметром -Qoption,cpp,--extended_float_type, который создает тип данных _Quad, представляющий собой 128-битную переменную с плавающей запятой. Мой пример SVD выглядит так:

#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;
}

скомпилировано с

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

Пока все работает нормально. Но вывод:

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

Я проверил, что U и VT верны, но сингулярные значения явно нет. Кто-нибудь знает, почему это происходит или как это можно обойти?
Спасибо за помощь.


person Maxwell    schedule 25.04.2012    source источник
comment
Правильно ли работает этот пример с обычной арифметикой двойной точности?   -  person ev-br    schedule 25.04.2012
comment
@ Женя Да, это так. Он вычисляет правильные сингулярные значения при вычислении с обычной двойной точностью. (4,23607, 0,236068)   -  person Maxwell    schedule 25.04.2012
comment
В этом случае я бы проверил подпрограмму DBDSQR: насколько я могу видеть из источника эталонной реализации (netlib.org/lapack/double/dgesvd.f), он вычисляет сингулярные значения с учетом матриц U и VT.   -  person ev-br    schedule 25.04.2012
comment
Какие вычисления вы выполняете, требующие 128-битной точности с плавающей запятой?   -  person Adrien    schedule 06.08.2012
comment
На самом деле я решил проблему на данный момент. К моему стыду, это произошло из-за ошибки, которую я внес в make.inc lapack, что привело к тому, что не все файлы были скомпилированы с параметром -r16. В частности, файлы, которые нужно было скомпилировать без оптимизации. У них есть дополнительная переменная параметров компиляции, которую я пропустил. Тем не менее, спасибо за вашу помощь.   -  person Maxwell    schedule 08.08.2012


Ответы (1)


При использовании внешних библиотек с повышенной точностью также проверьте, не используют ли они старый стиль d1mach.f, r1mach.f, i1mach.f для получения информации о машинной арифметике. Здесь могут быть некоторые значения для настройки.

Это не может быть проблемой с Lapack, который использует dlamch.f (здесь http://www.netlib.org/lapack/util/dlamch.f), который использует встроенные функции Fortran 90 для получения этих машинных констант.

Но это может стать проблемой, например, с BLAS или SLATEC, если вы их используете.

person Community    schedule 03.10.2012