Xấp xỉ một trường hợp đặc biệt của hàm Riemann Theta


27

Thách thức này là viết mã nhanh có thể thực hiện một tổng vô hạn khó tính toán.

Đầu vào

Một nbằng nma trận Pvới mục số nguyên nhỏ hơn 100về giá trị tuyệt đối. Khi kiểm tra tôi rất vui khi cung cấp đầu vào cho mã của bạn ở bất kỳ định dạng hợp lý nào mà mã của bạn muốn. Mặc định sẽ là một dòng trên mỗi hàng của ma trận, phân tách không gian và được cung cấp trên đầu vào tiêu chuẩn.

Psẽ là xác định tích cực mà ngụ ý nó sẽ luôn luôn đối xứng. Ngoài ra, bạn không thực sự cần biết ý nghĩa tích cực có nghĩa là gì để trả lời thử thách. Tuy nhiên, điều đó có nghĩa là thực sự sẽ có câu trả lời cho số tiền được xác định dưới đây.

Tuy nhiên, bạn cần phải biết sản phẩm vector ma trận là gì.

Đầu ra

Mã của bạn sẽ tính tổng vô hạn:

nhập mô tả hình ảnh ở đây

trong phạm vi cộng hoặc trừ 0,0001 của câu trả lời đúng. Dưới đây Zlà tập hợp các số nguyên và Z^ntất cả các vectơ có thể có các nphần tử nguyên và ehằng số toán học nổi tiếng xấp xỉ bằng 2.71828. Lưu ý rằng giá trị trong số mũ chỉ đơn giản là một số. Xem dưới đây cho một ví dụ rõ ràng.

Làm thế nào điều này liên quan đến chức năng Riemann Theta?

Trong ký hiệu của bài viết này về xấp xỉ hàm Riemann Theta, chúng tôi đang cố gắng tính toán nhập mô tả hình ảnh ở đây. Vấn đề của chúng tôi là một trường hợp đặc biệt vì ít nhất hai lý do.

  • Chúng tôi đặt tham số ban đầu được gọi ztrong bài báo được liên kết thành 0.
  • Chúng ta tạo ma trận Ptheo cách sao cho kích thước tối thiểu của một giá trị riêng 1. (Xem bên dưới để biết cách tạo ma trận.)

Ví dụ

P = [[ 5.,  2.,  0.,  0.],
     [ 2.,  5.,  2., -2.],
     [ 0.,  2.,  5.,  0.],
     [ 0., -2.,  0.,  5.]]

Output: 1.07551411208

Chi tiết hơn, chúng ta hãy xem chỉ một thuật ngữ trong tổng số P. Lấy ví dụ chỉ một thuật ngữ trong tổng:

nhập mô tả hình ảnh ở đây

x^T P x = 30. Lưu ý rằng đó e^(-30)là về 10^(-14)và vì vậy không chắc là quan trọng để có được câu trả lời chính xác cho đến dung sai cho trước. Hãy nhớ lại rằng tổng vô hạn sẽ thực sự sử dụng mọi vectơ có thể có độ dài 4 trong đó các phần tử là số nguyên. Tôi chỉ chọn một để đưa ra một ví dụ rõ ràng.

P = [[ 5.,  2.,  2.,  2.],
     [ 2.,  5.,  4.,  4.],
     [ 2.,  4.,  5.,  4.],
     [ 2.,  4.,  4.,  5.]]

Output = 1.91841190706

P = [[ 6., -3.,  3., -3.,  3.],
     [-3.,  6., -5.,  5., -5.],
     [ 3., -5.,  6., -5.,  5.],
     [-3.,  5., -5.,  6., -5.],
     [ 3., -5.,  5., -5.,  6.]]

Output = 2.87091065342

P = [[6., -1., -3., 1., 3., -1., -3., 1., 3.],
     [-1., 6., -1., -5., 1., 5., -1., -5., 1.],
     [-3., -1., 6., 1., -5., -1., 5., 1., -5.],
     [1., -5., 1., 6., -1., -5., 1., 5., -1.],
     [3., 1., -5., -1., 6., 1., -5., -1., 5.],
     [-1., 5., -1., -5., 1., 6., -1., -5., 1.],
     [-3., -1., 5., 1., -5., -1., 6., 1., -5.],
     [1., -5., 1., 5., -1., -5., 1., 6., -1.],
     [3., 1., -5., -1., 5., 1., -5., -1., 6.]]

Output: 8.1443647932

P = [[ 7.,  2.,  0.,  0.,  6.,  2.,  0.,  0.,  6.],
     [ 2.,  7.,  0.,  0.,  2.,  6.,  0.,  0.,  2.],
     [ 0.,  0.,  7., -2.,  0.,  0.,  6., -2.,  0.],
     [ 0.,  0., -2.,  7.,  0.,  0., -2.,  6.,  0.],
     [ 6.,  2.,  0.,  0.,  7.,  2.,  0.,  0.,  6.],
     [ 2.,  6.,  0.,  0.,  2.,  7.,  0.,  0.,  2.],
     [ 0.,  0.,  6., -2.,  0.,  0.,  7., -2.,  0.],
     [ 0.,  0., -2.,  6.,  0.,  0., -2.,  7.,  0.],
     [ 6.,  2.,  0.,  0.,  6.,  2.,  0.,  0.,  7.]]

Output = 3.80639191181

Ghi bàn

Tôi sẽ kiểm tra mã của bạn trên các ma trận được chọn ngẫu nhiên P có kích thước tăng dần.

Điểm của bạn chỉ đơn giản là lớn nhất nmà tôi nhận được câu trả lời đúng trong vòng chưa đầy 30 giây khi tính trung bình trên 5 lần chạy với ma trận được chọn ngẫu nhiên Pcó kích thước đó.

Cà vạt thì sao?

Nếu có hòa, người chiến thắng sẽ là người có mã chạy nhanh nhất trung bình trên 5 lần chạy. Trong trường hợp những thời điểm đó cũng bằng nhau, người chiến thắng là câu trả lời đầu tiên.

Làm thế nào đầu vào ngẫu nhiên sẽ được tạo ra?

  1. Đặt M là ma trận m by n ngẫu nhiên với m <= n và các mục nhập là -1 hoặc 1. Trong Python / numpy M = np.random.choice([0,1], size = (m,n))*2-1. Trong thực tế tôi sẽ thiết lập mvề n/2.
  2. Đặt P là ma trận danh tính + M ^ T M. Trong Python / numpy P =np.identity(n)+np.dot(M.T,M). Bây giờ chúng tôi được đảm bảo rằng đó Plà xác định tích cực và các mục trong một phạm vi phù hợp.

Lưu ý rằng điều này có nghĩa là tất cả các giá trị riêng của P ít nhất là 1, làm cho vấn đề có thể dễ dàng hơn so với vấn đề chung là xấp xỉ hàm Riemann Theta.

Ngôn ngữ và thư viện

Bạn có thể sử dụng bất kỳ ngôn ngữ hoặc thư viện nào bạn thích. Tuy nhiên, với mục đích ghi điểm, tôi sẽ chạy mã của bạn trên máy của mình, vì vậy vui lòng cung cấp hướng dẫn rõ ràng về cách chạy mã trên Ubuntu.

Máy của tôi Thời gian sẽ được chạy trên máy của tôi. Đây là bản cài đặt Ubuntu tiêu chuẩn trên Bộ xử lý tám lõi AMD FX-8350. Điều này cũng có nghĩa là tôi cần để có thể chạy mã của bạn.


Câu trả lời hàng đầu

  • n = 47trong C ++ của TonMedel
  • n = 8trong Python của Maltysen

Có thể đáng nói là một ma trận xác định dương là đối xứng theo định nghĩa.
2012rcampion

@ 2012rcampion Cảm ơn. Thêm.

Ok, có lẽ đây là một câu hỏi ngớ ngẩn, nhưng tôi đã nhìn chằm chằm vào này cho các lứa tuổi và tôi không thể tìm ra cách bạn nhận được một xsố [-1,0,2,1]. bạn có thể xây dựng trên này? (Gợi ý: Tôi không phải là một chuyên gia toán học)
wnnmaw

@wnnmaw Xin lỗi vì đã nhầm lẫn. Tổng có một số hạng cho mọi vectơ có thể có độ dài 4 trong trường hợp này. [-1,0,2,1] chỉ là một cái tôi chọn ngẫu nhiên để hiển thị rõ ràng thuật ngữ này sẽ là gì trong trường hợp đó.

1
@Lembik Cách bạn tạo ma trận SPD ngụ ý rằng không có giá trị số ít nào có giá trị tuyệt đối dưới 1. Chúng ta có thể sử dụng kiến ​​thức đó không?
flawr

Câu trả lời:


15

C ++

Không còn cách tiếp cận ngây thơ. Chỉ đánh giá bên trong ellipsoid.

Sử dụng các thư viện armadillo, ntl, gsl và pthread. Cài đặt bằng

apt-get install libarmadillo-dev libntl-dev libgsl-dev

Biên dịch chương trình bằng cách sử dụng một cái gì đó như:

g++ -Wall -std=c++11 -O3 -fno-math-errno -funsafe-math-optimizations -ffast-math -fno-signed-zeros -fno-trapping-math -fomit-frame-pointer -march=native -s infinity.cpp -larmadillo -lntl -lgsl -lpthread -o infinity

Trên một số hệ thống, bạn có thể cần phải thêm -lgslcblassau -lgsl.

Chạy với kích thước của ma trận theo sau là các phần tử trên STDIN:

./infinity < matrix.txt

matrix.txt:

4
5  2  0  0
2  5  2 -2
0  2  5  0
0 -2  0  5

Hoặc để thử độ chính xác 1e-5:

./infinity -p 1e-5 < matrix.txt

infinity.cpp:

// Based on http://arxiv.org/abs/nlin/0206009

#include <iostream>
#include <vector>
#include <stdexcept>
#include <cstdlib>
#include <cmath>
#include <string>
#include <thread>
#include <future>
#include <chrono>

using namespace std;

#include <getopt.h>

#include <armadillo>

using namespace arma;

#include <NTL/mat_ZZ.h>
#include <NTL/LLL.h>

using namespace NTL;

#include <gsl/gsl_sf_gamma.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_roots.h>

double const EPSILON = 1e-4;       // default precision
double const GROW    = 2;          // By how much we grow the ellipsoid volume
double const UPSCALE = 1e9;        // lattice reduction, upscale real to integer
double const THREAD_SEC = 0.1;     // Use threads if need more time than this
double const RADIUS_MAX = 1e6;     // Maximum radius used in root finding
double const RADIUS_INTERVAL = 1e-6; // precision of target radius
int const ITER_MAX = 1000;         // Maximum iterations in root finding
unsigned long POINTS_MIN = 1000;   // Minimum points before getting fancy

struct Result {
    Result& operator+=(Result const& add) {
        sum     += add.sum;
        elapsed += add.elapsed;
        points  += add.points;
        return *this;
    }

    friend Result operator-(Result const& left, Result const& right) {
        return Result{left.sum - right.sum,
                left.elapsed - right.elapsed,
                left.points - right.points};
    }

    double sum, elapsed;
    unsigned long points;
};

struct Params {
    double half_rho, half_N, epsilon;
};

double fill_factor_error(double r, void *void_params) {
    auto params = static_cast<Params*>(void_params);
    r -= params->half_rho;
    return gsl_sf_gamma_inc(params->half_N, r*r) - params->epsilon;
}

// Calculate radius needed for target precision
double radius(int N, double rho, double lat_det, double epsilon) {
    Params params;

    params.half_rho = rho / 2.;
    params.half_N   = N   / 2.;
    params.epsilon = epsilon*lat_det*gsl_sf_gamma(params.half_N)/pow(M_PI, params.half_N);

    // Calculate minimum allowed radius
    auto r = sqrt(params.half_N)+params.half_rho;
    auto val = fill_factor_error(r, &params);
    cout << "Minimum R=" << r << " -> " << val << endl;

    if (val > 0) {
        // The minimum radius is not good enough. Work out a better one by
        // finding the root of a tricky function
        auto low  = r;
        auto high = RADIUS_MAX * 2 * params.half_rho;
        auto val = fill_factor_error(high, &params);
        if (val >= 0)
            throw(logic_error("huge RADIUS_MAX is still not big enough"));

        gsl_function F;
        F.function = fill_factor_error;
        F.params   = &params;

        auto T = gsl_root_fsolver_brent;
        auto s = gsl_root_fsolver_alloc (T);
        gsl_root_fsolver_set (s, &F, low, high);

        int status = GSL_CONTINUE;
        for (auto iter=1; status == GSL_CONTINUE && iter <= ITER_MAX; ++iter) {
            gsl_root_fsolver_iterate (s);
            low  = gsl_root_fsolver_x_lower (s);
            high = gsl_root_fsolver_x_upper (s);
            status = gsl_root_test_interval(low, high, 0, RADIUS_INTERVAL  * 2 * params.half_rho);
        }
        r = gsl_root_fsolver_root(s);
        gsl_root_fsolver_free(s);
        if (status == GSL_CONTINUE)
            throw(logic_error("Search for R did not converge"));
    }
    return r;
}

// Recursively walk down the ellipsoids in each dimension
void ellipsoid(int d, mat const& A, double const* InvD, mat& Accu,
               Result& result, double r2) {
    auto r = sqrt(r2);
    auto offset = Accu(d, d);
    // InvD[d] = 1/ A(d, d)
    auto from = ceil((-r-offset) * InvD[d]);
    auto to   = floor((r-offset) * InvD[d]);
    for (auto v = from; v <= to; ++v) {
        auto value  = v * A(d, d)+offset;
        auto residu = r2 - value*value;
        if (d == 0) {
            result.sum += exp(residu);
            ++result.points;
        } else {
            for (auto i=0; i<d; ++i) Accu(d-1, i) = Accu(d, i) + v * A(d, i);
            ellipsoid(d-1, A, InvD, Accu, result, residu);
        }
    }
}

// Specialised version of ellipsoid() that will only process points an octant
void ellipsoid(int d, mat const& A, double const* InvD, mat& Accu,
               Result& result, double r2, unsigned int octant) {
    auto r = sqrt(r2);
    auto offset = Accu(d, d);
    // InvD[d] = 1/ A(d, d)
    long from = ceil((-r-offset) * InvD[d]);
    long to   = floor((r-offset) * InvD[d]);
    auto points = to-from+1;
    auto base = from + points/2;
    if (points & 1) {
        auto value = base * A(d, d) + offset;
        auto residu = r2 - value * value;
        if (d == 0) {
            if ((octant & (octant - 1)) == 0) {
                result.sum += exp(residu);
                ++result.points;
            }
        } else {
            for (auto i=0; i<d; ++i) Accu(d-1, i) = Accu(d, i) + base * A(d, i);
            ellipsoid(d-1, A, InvD, Accu, result, residu, octant);
        }
        ++base;
    }
    if ((octant & 1) == 0) {
        to = from + points / 2 - 1;
        base = from;
    }
    octant /= 2;
    for (auto v = base; v <= to; ++v) {
        auto value = v * A(d,d)+offset;
        auto residu = r2 - value*value;
        if (d == 0) {
            if ((octant & (octant - 1)) == 0) {
                result.sum += exp(residu);
                ++result.points;
            }
        } else {
            for (auto i=0; i<d; ++i) Accu(d-1, i) = Accu(d, i) + v * A(d, i);
            if (octant == 1)
                ellipsoid(d-1, A, InvD, Accu, result, residu);
            else
                ellipsoid(d-1, A, InvD, Accu, result, residu, octant);
        }
    }
}

// Prepare call to ellipsoid()
Result sym_ellipsoid(int N, mat const& A, const vector<double>& InvD, double r,
                     unsigned int octant = 1) {
    auto start = chrono::steady_clock::now();
    auto r2 = r*r;

    mat Accu(N, N);
    Accu.row(N-1).zeros();

    Result result{0, 0, 0};
    // 2*octant+1 forces the points into the upper half plane, skipping 0
    // This way we use the lattice symmetry and calculate only half the points
    ellipsoid(N-1, A, &InvD[0], Accu, result, r2, 2*octant+1);
    // Compensate for the extra factor exp(r*r) we always add in ellipsoid()
    result.sum /= exp(r2);
    auto end = chrono::steady_clock::now();
    result.elapsed = chrono::duration<double>{end-start}.count();

    return result;
}

// Prepare multithreaded use of sym_ellipsoid(). Each thread gets 1 octant
Result sym_ellipsoid_t(int N, mat const& A, const vector<double>& InvD, double r, unsigned int nr_threads) {
    nr_threads = pow(2, ceil(log2(nr_threads)));

    vector<future<Result>> results;
    for (auto i=nr_threads+1; i<2*nr_threads; ++i)
        results.emplace_back(async(launch::async, sym_ellipsoid, N, ref(A), ref(InvD), r, i));
    auto result = sym_ellipsoid(N, A, InvD, r, nr_threads);
    for (auto i=0U; i<nr_threads-1; ++i) result += results[i].get();
    return result;
}

int main(int argc, char* const* argv) {
    cin.exceptions(ios::failbit | ios::badbit);
    cout.precision(12);

    double epsilon    = EPSILON; // Target absolute error
    bool inv_modular  = true;    // Use modular transform to get the best matrix
    bool lat_reduce   = true;    // Use lattice reduction to align the ellipsoid
    bool conservative = false;   // Use provable error bound instead of a guess
    bool eigen_values = false;   // Show eigenvalues
    int  threads_max  = thread::hardware_concurrency();

    int option_char;
    while ((option_char = getopt(argc, argv, "p:n:MRce")) != EOF)
        switch (option_char) {
            case 'p': epsilon      = atof(optarg); break;
            case 'n': threads_max  = atoi(optarg); break;
            case 'M': inv_modular  = false;        break;
            case 'R': lat_reduce   = false;        break;
            case 'c': conservative = true;         break;
            case 'e': eigen_values = true;         break;
            default:
              cerr << "usage: " << argv[0] << " [-p epsilon] [-n threads] [-M] [-R] [-e] [-c]" << endl;
              exit(EXIT_FAILURE);
        }
    if (optind < argc) {
        cerr << "Unexpected argument" << endl;
        exit(EXIT_FAILURE);
    }
    if (threads_max < 1) threads_max = 1;
    threads_max = pow(2, ceil(log2(threads_max)));
    cout << "Using up to " << threads_max << " threads" << endl;

    int N;
    cin >> N;

    mat P(N, N);
    for (auto& v: P) cin >> v;

    if (eigen_values) {
        vec eigval = eig_sym(P);
        cout << "Eigenvalues:\n" << eigval << endl;
    }

    // Decompose P = A * A.t()
    mat A = chol(P, "lower");

    // Calculate lattice determinant
    double lat_det = 1;
    for (auto i=0; i<N; ++i) {
        if (A(i,i) <= 0) throw(logic_error("Diagonal not Positive"));
        lat_det *= A(i,i);
    }
    cout << "Lattice determinant=" << lat_det << endl;

    auto factor = lat_det / pow(M_PI, N/2.0);
    if (inv_modular && factor < 1) {
        epsilon *= factor;
        cout << "Lattice determinant is small. Using inverse instead. Factor=" << factor << endl;
        P = M_PI * M_PI * inv(P);
        A = chol(P, "lower");
        // We could simple calculate the new lat_det as pow(M_PI,N)/lat_det
        lat_det = 1;
        for (auto i=0; i<N; ++i) {
            if (A(i,i) <= 0) throw(logic_error("Diagonal not Positive"));
            lat_det *= A(i,i);
        }
        cout << "New lattice determinant=" << lat_det << endl;
    } else
        factor = 1;

    // Prepare for lattice reduction.
    // Since the library works on integer lattices we will scale up our matrix
    double min = INFINITY;
    for (auto i=0; i<N; ++i) {
        for (auto j=0; j<N;++j)
            if (A(i,j) != 0 && abs(A(i,j) < min)) min = abs(A(i,j));
    }

    auto upscale = UPSCALE/min;
    mat_ZZ a;
    a.SetDims(N,N);
    for (auto i=0; i<N; ++i)
        for (auto j=0; j<N;++j) a[i][j] = to_ZZ(A(i,j)*upscale);

    // Finally do the actual lattice reduction
    mat_ZZ u;
    auto rank = G_BKZ_FP(a, u);
    if (rank != N) throw(logic_error("Matrix is singular"));
    mat U(N,N);
    for (auto i=0; i<N;++i)
        for (auto j=0; j<N;++j) U(i,j) = to_double(u[i][j]);

    // There should now be a short lattice vector at row 0
    ZZ sum = to_ZZ(0);
    for (auto j=0; j<N;++j) sum += a[0][j]*a[0][j];
    auto rho = sqrt(to_double(sum))/upscale;
    cout << "Rho=" << rho << " (integer square " <<
        rho*rho << " ~ " <<
        static_cast<int>(rho*rho+0.5) << ")" << endl;

    // Lattice reduction doesn't gain us anything conceptually.
    // The same number of points is evaluated for the same exponential values
    // However working through the ellipsoid dimensions from large lattice
    // base vectors to small makes ellipsoid() a *lot* faster
    if (lat_reduce) {
        mat B = U * A;
        P = B * B.t();
        A = chol(P, "lower");
        if (eigen_values) {
            vec eigval = eig_sym(P);
            cout << "New eigenvalues:\n" << eigval << endl;
        }
    }

    vector<double> InvD(N);;
    for (auto i=0; i<N; ++i) InvD[i] = 1 / A(i, i);

    // Calculate radius needed for target precision
    auto r = radius(N, rho, lat_det, epsilon);
    cout << "Safe R=" << r << endl;

    auto nr_threads = threads_max;
    Result result;
    if (conservative) {
        // Walk all points inside the ellipsoid with transformed radius r
        result = sym_ellipsoid_t(N, A, InvD, r, nr_threads);
    } else {
        // First grow the radius until we saw POINTS_MIN points or reach the
        // target radius
        double i = floor(N * log2(r/rho) / log2(GROW));
        if (i < 0) i = 0;
        auto R = r * pow(GROW, -i/N);
        cout << "Initial R=" << R << endl;
        result = sym_ellipsoid_t(N, A, InvD, R, nr_threads);
        nr_threads = result.elapsed < THREAD_SEC ? 1 : threads_max;
        auto max_new_points = result.points;
        while (--i >= 0 && result.points < POINTS_MIN) {
            R = r * pow(GROW, -i/N);
            auto change = result;
            result = sym_ellipsoid_t(N, A, InvD, R, nr_threads);
            nr_threads = result.elapsed < THREAD_SEC ? 1 : threads_max;
            change = result - change;

            if (change.points > max_new_points) max_new_points = change.points;
        }

        // Now we have enough points that it's worth bothering to use threads
        while (--i >= 0) {
            R = r * pow(GROW, -i/N);
            auto change = result;
            result = sym_ellipsoid_t(N, A, InvD, R, nr_threads);
            nr_threads = result.elapsed < THREAD_SEC ? 1 : threads_max;
            change = result - change;
            // This is probably too crude and might misestimate the error
            // I've never seen it fail though
            if (change.points > max_new_points) {
                max_new_points = change.points;
                if (change.sum < epsilon/2) break;
            }
        }
        cout << "Final R=" << R << endl;
    }

    // We calculated half the points and skipped 0.
    result.sum = 2*result.sum+1;

    // Modular transform factor
    result.sum /= factor;

    // Report result
    cout <<
        "Evaluated " << result.points << " points\n" <<
        "Sum = " << result.sum << endl;
}

Điều này rất ấn tượng và tốt hơn nhiều so với cách tiếp cận ngây thơ trong quan điểm của tôi. Tôi mong chờ tài liệu :)

1
@TonHeach Bạn có thể cho chúng tôi biết thêm một chút về cách bạn đưa ra giới hạn không?
flawr

2
Tôi đang sử dụng Arch Linux và cần -lgslcblascờ để biên dịch. Bằng cách trả lời tuyệt vời!
Rhyzomatic

2

Con trăn 3

12 giây n = 8 trên máy tính của tôi, lõi 4 của Ubuntu.

Thực sự ngây thơ, không biết tôi đang làm gì.

from itertools import product
from math import e

P = [[ 6., -3.,  3., -3.,  3.],
     [-3.,  6., -5.,  5., -5.],
     [ 3., -5.,  6., -5.,  5.],
     [-3.,  5., -5.,  6., -5.],
     [ 3., -5.,  5., -5.,  6.]]

N = 2

n = [1]

while e** -n[-1] > 0.0001:
    n = []
    for x in product(list(range(-N, N+1)), repeat = len(P)):
        n.append(sum(k[0] * k[1] for k in zip([sum(j[0] * j[1] for j in zip(i, x)) for i in P], x)))
    N += 1

print(sum(e** -i for i in n))

Điều này sẽ tiếp tục tăng phạm vi Zmà nó sử dụng cho đến khi nhận được câu trả lời đủ tốt. Tôi đã viết phép nhân ma trận của riêng tôi, prolly nên sử dụng numpy.


Cảm ơn ! Bạn có thể hiển thị một số đầu ra và thời gian trên máy tính của bạn?

Mã của bạn chạy trong pypy, đó là tuyệt vời và nhanh chóng. Thật không may, [[6.0, -1.0, -3.0, 1.0, 3.0, -1.0, -3.0, 1.0, 3.0], [-1.0, 6.0, -1.0, -5.0, 1.0, 5.0, -1.0, -5.0, 1.0 ], [-3.0, -1.0, 6.0, 1.0, -5.0, -1.0, 5.0, 1.0, -5.0], [1.0, -5.0, 1.0, 6.0, -1.0, -5.0, 1.0, 5.0, -1.0] , [3.0, 1.0, -5.0, -1.0, 6.0, 1.0, -5.0, -1.0, 5.0], [-1.0, 5.0, -1.0, -5.0, 1.0, 6.0, -1.0, -5.0, 1.0], [-3.0, -1.0, 5.0, 1.0, -5.0, -1.0, 6.0, 1.0, -5.0], [1.0, -5.0, 1.0, 5.0, -1.0, -5.0, 1.0, 6.0, -1.0], [ 3.0, 1.0, -5.0, -1.0, 5.0, 1.0, -5.0, -1.0, 6.0]] chỉ đưa ra câu trả lời sai.

8.1443647932-8.14381938863 = 0.00054540456> 0,0001.

3
@Maltysen Chương trình của bạn chỉ kiểm tra xem thuật ngữ cuối cùng có nhỏ hơn độ chính xác đã cho hay không. Nhưng lỗi bạn mắc phải còn lớn hơn nhiều, vì bạn cũng phải xem xét tổng của tất cả các điều khoản khác cho lỗi đó!
flawr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.