Perhitungan cepat rumus dari Excel dalam C #

Seberapa sering Anda mendengar dari pelanggan bahwa mereka akan mengirim data ke Excel atau meminta Anda untuk mengimpor atau mengunggah dalam format yang kompatibel dengan Excel? Saya yakin bahwa di sebagian besar area, Excel adalah salah satu alat yang paling populer, kuat, dan sekaligus sederhana dan nyaman. Tetapi titik yang paling bermasalah adalah selalu integrasi data tersebut dengan berbagai sistem otomatis. Tim kami diminta untuk mempertimbangkan kemungkinan melakukan perhitungan data menggunakan pengaturan dari file Excel khusus.

Perhitungan cepat rumus dari Excel dalam C #

Jika Anda perlu memilih perpustakaan yang produktif untuk bekerja dengan file Excel atau jika Anda mencari solusi untuk menghitung data keuangan yang kompleks (dan tidak hanya) dengan alat yang nyaman untuk mengelola dan memvisualisasikan rumus di luar kotak, selamat datang di cat.

Mempelajari persyaratan proyek baru di perusahaan, kami menemukan satu hal yang sangat menarik: "Solusi yang dikembangkan harus dapat menghitung biaya produk (yaitu, balkon) ketika mengubah konfigurasi dan langsung menampilkan biaya baru pada antarmuka. Penting untuk menyediakan kemampuan untuk mengunduh file Excel dengan semua fungsi perhitungan dan daftar harga komponen. " Klien perlu mengembangkan portal untuk merancang konfigurasi balkon tergantung pada ukuran, bentuk, jenis kaca dan bahan yang digunakan, jenis pengikat, serta banyak parameter terkait lainnya yang digunakan untuk menghitung biaya produksi dan indikator keandalan yang tepat.

Kami memformalkan persyaratan input sehingga lebih mudah untuk memahami dalam konteks mana diperlukan untuk menyelesaikan masalah:

  • Penghitungan cepat harga pada antarmuka saat mengubah parameter balkon;
  • Perhitungan cepat data desain, termasuk berbagai konfigurasi balkon dan penawaran individual, disediakan oleh file perhitungan terpisah;
  • Dalam jangka panjang - pengembangan fungsionalitas menggunakan berbagai operasi yang memakan sumber daya (tugas mengoptimalkan parameter, dll.)
  • Semua ini ada di server jauh dengan output melalui API, karena Semua formula adalah properti intelektual pelanggan dan tidak boleh terlihat oleh pihak ketiga;
  • Aliran data input dengan beban puncak: pengguna dapat sering dan cepat mengubah parameter untuk memilih konfigurasi produk sesuai dengan persyaratan mereka.

Kedengarannya sangat tidak biasa dan sangat menggoda, mari kita mulai!

Solusi turnkey dan persiapan data


Setiap penelitian untuk memecahkan masalah yang rumit dimulai dengan berselancar di StackOverflow, GitHub dan banyak forum mencari solusi yang sudah jadi.

Beberapa solusi siap pakai dipilih yang mendukung pembacaan data dari file Excel, serta mampu melakukan perhitungan berdasarkan formula yang ditentukan di dalam perpustakaan. Di antara perpustakaan-perpustakaan ini ada solusi gratis dan pengembangan komersial. 


Langkah selanjutnya adalah menulis tes beban dan mengukur runtime dari masing-masing perpustakaan. Untuk melakukan ini, siapkan data uji. Kami membuat file Excel baru, menetapkan 10 sel untuk parameter input dan satu ( ingat saat ini ) formula untuk mendapatkan hasil yang menggunakan semua parameter input. Dalam rumus, kami mencoba menggunakan semua fungsi matematika yang mungkin dari berbagai kompleksitas komputasi dan menggabungkannya dengan cara yang rumit.

Karena itu juga tentang uang (biaya produk), penting untuk melihat keakuratan hasil. Dalam hal ini, kami akan mengambil nilai yang dihasilkan yang diperoleh menggunakan Excel Interop sebagai referensikarena Data yang diperoleh dengan cara ini dihitung melalui inti Excel dan sama dengan nilai yang dilihat pelanggan ketika mengembangkan formula dan secara manual menghitung biaya. 

Sebagai runtime referensi, kami akan menggunakan kode asli yang ditulis secara manual dalam C # murni untuk menampilkan rumus yang sama yang ditulis dalam Excel.

Formula Tes Awal Diterjemahkan:

public double Execute(double[] p)
{
    return Math.Pow(p[0] * p[8] / p[4] * Math.Sin(p[5]) * Math.Cos(p[2]) +
                          Math.Abs(p[1] - (p[2] + p[3] + p[4] + p[5] + p[6] + p[7] + p[8]))
                          * Math.Sqrt(p[0] * p[0] + p[1] * p[1]) / 2.0 * Math.PI, p[9]);
}

Kami membentuk aliran data input acak untuk iterasi N (dalam hal ini, kami menggunakan 10.000 vektor).

Kami memulai perhitungan untuk setiap vektor parameter input pada keseluruhan aliran, mendapatkan hasil dan mengukur waktu inisialisasi perpustakaan dan perhitungan umum.

Untuk membandingkan akurasi hasil, kami menggunakan dua indikator - standar deviasi dan persentase nilai yang cocok dengan langkah akurasi tertentu epsilon. Jika Anda secara acak membuat daftar nilai input dengan titik mengambang setelah titik desimal, Anda harus menentukan keakuratan parameter input - ini akan memungkinkan Anda untuk mendapatkan hasil yang benar. Jika tidak, angka acak dapat memiliki perbedaan besar urutan besarnya - ini dapat sangat mempengaruhi keakuratan hasil dan mempengaruhi estimasi kesalahan hasil.

Karena Awalnya, kami mengasumsikan bahwa diperlukan untuk beroperasi dengan nilai konstan dari biaya bahan, serta beberapa konstanta dari berbagai bidang pengetahuan, kami dapat menerima bahwa semua parameter input akan memiliki nilai yang akurat hingga 3 tempat desimal. Idealnya, Anda perlu menentukan rentang nilai yang valid untuk masing-masing parameter dan hanya menggunakannya untuk menghasilkan nilai acak, tetapi sejak itu rumus untuk pengujian dikompilasi secara acak tanpa pembenaran matematis dan fisik, maka tidak mungkin untuk menghitung kisaran nilai untuk semua 10 parameter dalam periode waktu yang wajar. Oleh karena itu, dalam perhitungan kadang-kadang dimungkinkan untuk mendapatkan kesalahan perhitungan. Kami mengecualikan vektor input data tersebut pada saat perhitungan untuk indikator akurasi,tetapi kami akan menghitung kesalahan tersebut sebagai karakteristik yang terpisah.

Arsitektur Uji 


Untuk setiap pustaka terpisah, kelasnya sendiri telah dibuat yang mengimplementasikan antarmuka ITestExecutor yang mencakup 3 metode - SetUp, Execute dan TearDown.

public interface ITestExecutor
{
    //      
    void SetUp();
    //   ,           
    double Execute(double[] p);
    //    ,      
    void TearDown();
}

Metode SetUpdan TearDownhanya digunakan sekali dalam proses pengujian perpustakaan dan tidak dipertimbangkan ketika mengukur perhitungan waktu pada seluruh rangkaian data input.

Akibatnya, algoritma pengujian diringkas menjadi sebagai berikut:

  • Persiapan data (kami membentuk aliran input vektor dengan akurasi tertentu);
  • Alokasi memori untuk data yang dihasilkan (array hasil untuk setiap perpustakaan, array dengan jumlah kesalahan); 
  • Inisialisasi perpustakaan;
  • Memperoleh hasil perhitungan untuk masing-masing perpustakaan dengan menyimpan hasilnya dalam array yang disiapkan sebelumnya dan mencatat waktu pelaksanaan;
  • Penyelesaian pekerjaan dengan kode perpustakaan;
  • Analisis data:

Representasi grafis dari algoritma ini disajikan di bawah ini.

Bagan alur pengujian kinerja dan akurasi perpustakaan dukungan Excel


Hasil iterasi pertama


IndeksAsliEPPlus 4
& EPPlus 5
NPOIPuncak menaraExcel interop
Waktu inisialisasi (ms)02572666321653
Mengawinkan waktu untuk 1 pass (ms)0,00020,40860,68476.978238.8423
Rata-rata deviasi0,0003940,0003950,0002370,000631t / a
Ketepatan99,99%99,92%99,97%99,84%t / a
Kesalahan0,0%1,94%1,94%1,52%1,94%

Mengapa hasil EPPlus 5 dan EPPlus 4 digabungkan?
EPPlus . , , . , . EPPlus 5 , . , EPPlus, .

Iterasi pertama dari tes menunjukkan hasil yang baik, di mana para pemimpin di antara perpustakaan segera terlihat. Seperti dapat dilihat dari data di atas, pemimpin absolut dalam situasi ini adalah perpustakaan EPPlus.

Hasilnya tidak mengesankan dibandingkan dengan kode asli, tetapi Anda dapat hidup.

Ini bisa saja dihentikan, tetapi setelah berbicara dengan pelanggan, keraguan pertama muncul: hasilnya terlalu bagus.


Fitur bekerja dengan perpustakaan Spire
Spire , InvalidCastException. , Excel- , , , . try...catch. , .

Rake iterasi tes pertama


Di atas, saya meminta Anda untuk menarik perhatian Anda ke satu titik yang memainkan peran penting dalam mendapatkan hasil. Kami menduga bahwa formula yang digunakan dalam file Excel sebenarnya dari pelanggan akan jauh dari primitif, dengan banyak dependensi di dalamnya, tetapi kami tidak menduga bahwa ini dapat sangat mempengaruhi indikator. Namun demikian, pada awalnya, ketika menyusun data pengujian, saya tidak melihat ini, dan data dari pelanggan (setidaknya informasi bahwa setidaknya 120 parameter input digunakan dalam file akhir) mengisyaratkan bahwa kita perlu berpikir dan menambahkan formula dengan dependensi antar sel. .

Kami mulai menyiapkan data baru untuk iterasi pengujian berikutnya. Mari kita membahas 10 parameter input dan menambahkan 4 formula baru tambahan dengan ketergantungan hanya pada parameter dan 1 formula agregasi, yang didasarkan pada empat sel ini dengan formula dan juga akan bergantung pada nilai-nilai data input.

Formula baru yang akan digunakan untuk pengujian selanjutnya:

public double Execute(double[] p)
{
    var price1 = Math.Pow(p[0] * p[8] / p[4] * Math.Sin(p[5]) * Math.Cos(p[2]) +
                          Math.Abs(p[1] - (p[2] + p[3] + p[4] + p[5] + p[6] + p[7] + p[8]))
                          * Math.Sqrt(p[0] * p[0] + p[1] * p[1]) / 2.0 * Math.PI, p[9]);

    var price2 = p[4] * p[5] * p[2] / Math.Max(1, Math.Abs(p[7]));

    var price3 = Math.Abs(p[7] - p[3]) * p[2];

    var price4 = Math.Sqrt(Math.Abs(p[1] * p[2] + p[3] * p[4] + p[5] * p[6]) + 1.0);

    var price5 = p[0] * Math.Cos(p[1]) + p[2] * Math.Sin(p[1]);

    var sum = p[0] + p[1] + p[2] + p[3] + p[4] + p[5] + p[6] + p[7] + p[8] + p[9];

    var price6 = sum / Math.Max(1, Math.Abs((p[0] + p[1] + p[2] + p[3]) / 4.0))
                 + sum / Math.Max(1, Math.Abs((p[4] + p[5] + p[6] + p[7] + p[8] + p[9]) / 6.0));

    var pricingAverage = (price1 + price2 + price3 + price4 + price5 + price6) / 6.0;

    return pricingAverage / Math.Max(1, Math.Abs(price1 + price2 + price3 + price4 + price5 + price6));
}

Seperti yang Anda lihat, formula yang dihasilkan ternyata jauh lebih rumit, yang secara alami memengaruhi hasil - bukan untuk yang lebih baik. Tabel dengan hasilnya disajikan di bawah ini:

IndeksAsliEPPlus 4 EPPlus 5NPOIPuncak menaraExcel interop
Waktu inisialisasi (ms)02413687221640
Mengawinkan waktu untuk 1 pass (ms)0,00040,9174 (+ 124%)1,8996 (+ 177%)7,7647 (+ 11%)50.7194 (+ 30%)
Rata-rata deviasi0,0358840,0000000,0000000,000000t / a
Ketepatan98,79%100,00%100,00%100,00%t / a
Kesalahan0,0%0,3%0,3%0,28%0,3%


Catatan: Karena Excel Interop terlalu besar, harus dikeluarkan dari bagan.

Seperti dapat dilihat dari hasilnya, situasinya menjadi sangat tidak cocok untuk digunakan dalam produksi. Sedikit sedih, persediaan kopi dan menyelam lebih dalam ke studi - langsung ke generasi kode. 


Pembuatan Kode


Jika Anda tiba-tiba tidak pernah menghadapi tugas serupa, maka kami akan melakukan perjalanan singkat. 

Pembuatan kode adalah cara menyelesaikan masalah dengan secara dinamis menghasilkan kode sumber berdasarkan input data dengan kompilasi dan eksekusi selanjutnya. Ada kedua pembuatan kode statis yang terjadi selama pembangunan proyek (saya dapat mengutip T4MVC sebagai contoh, yang membuat kode baru berdasarkan template dan metadata yang dapat digunakan saat menulis kode aplikasi utama), dan kode dinamis yang berjalan selama runtime. 

Tugas kami adalah membentuk fungsi baru berdasarkan data sumber (rumus dari Excel), yang menerima hasil berdasarkan vektor nilai input.

Untuk melakukan ini, Anda harus:

  • Baca rumus dari file;
  • Kumpulkan semua dependensi;
  • C#;
  • ;
  • ;
  • .

Semua perpustakaan yang disajikan cocok untuk membaca rumus, namun, perpustakaan EPPlus ternyata merupakan antarmuka yang paling nyaman untuk fungsi tersebut . Setelah mencari-cari sedikit dalam kode sumber perpustakaan ini, saya menemukan kelas publik untuk membentuk daftar token dan transformasi lebih lanjut menjadi pohon ekspresi. Bingo, pikirku! Pohon ekspresi siap pakai dari kotak sangat ideal, cukup telusuri dan bentuk kode C # kami. 

Tetapi tangkapan besar sedang menunggu saya ketika saya mulai mempelajari node dari pohon ekspresi yang dihasilkan. Beberapa node, khususnya panggilan ke fungsi Excel, merangkum informasi tentang fungsi yang digunakan dan parameter inputnya dan tidak menyediakan akses terbuka ke data ini. Oleh karena itu, pekerjaan dengan pohon ekspresi selesai harus ditunda.

Kami naik satu tingkat lebih rendah dan mencoba bekerja dengan daftar token. Semuanya cukup sederhana di sini: kami memiliki token yang memiliki jenis dan nilai. Karena kita diberi fungsi dan kita perlu membentuk fungsi, maka kita bisa mengonversi token pohon menjadi setara di C #. Hal utama dalam pendekatan ini adalah mengatur fungsi yang kompatibel. Sebagian besar fungsi matematika sudah kompatibel - seperti menghitung cosinus, sinus, mendapatkan root, dan menaikkan ke kekuatan. Tetapi fungsi agregasi - seperti nilai maksimum, minimum, jumlah - perlu diselesaikan. Perbedaan utama adalah bahwa di Excel, fungsi-fungsi ini bekerja dengan rentang nilai. Untuk kesederhanaan prototipe, kami akan membuat fungsi yang mengambil daftar parameter sebagai input, yang sebelumnya memperluas rentang nilai ke dalam daftar linier.Dengan cara ini kita mendapatkan konversi yang benar dan kompatibel dari sintaks Excel ke sintaks C #. 

Di bawah ini adalah kode utama untuk mengonversi daftar token dari rumus Excel menjadi kode C # yang valid.

private string TransformToSharpCode(string formula, ParsingContext parsingContext)
{
    // Initialize basic compile components, e.g. lexer
    var lexer = new Lexer(parsingContext.Configuration.FunctionRepository, parsingContext.NameValueProvider);

    // List of dependency variables that can be filled during formula transformation
    var variables = new Dictionary<string, string>();
    using (var scope = parsingContext.Scopes.NewScope(RangeAddress.Empty))
    {
        // Take resulting code line
        var compiledResultCode = TransformToSharpCode(formula, parsingContext, scope, lexer, variables);

        var output = new StringBuilder();

        // Define dependency variables in reverse order.
        foreach (var variableDefinition in variables.Reverse())
        {
            output.AppendLine($"var {variableDefinition.Key} = {variableDefinition.Value};");
        }

        // Take the result
        output.AppendLine($"return {compiledResultCode};");

        return output.ToString();
    }
}

private string TransformToSharpCode(ICollection<Token> tokens, ParsingContext parsingContext, ParsingScope scope, ILexer lexer, Dictionary<string, string> variables)
{
    var output = new StringBuilder();

    foreach (Token token in tokens)
    {
        switch (token.TokenType)
        {
            case TokenType.Function:
                output.Append(BuildFunctionName(token.Value));
                break;
            case TokenType.OpeningParenthesis:
                output.Append("(");
                break;
            case TokenType.ClosingParenthesis:
                output.Append(")");
                break;
            case TokenType.Comma:
                output.Append(", ");
                break;
            case TokenType.ExcelAddress:
                var address = token.Value;
                output.Append(TransformAddressToSharpCode(address, parsingContext, scope, lexer, variables));
                break;
            case TokenType.Decimal:
            case TokenType.Integer:
            case TokenType.Boolean:
                output.Append(token.Value);
                break;
            case TokenType.Operator:
                output.Append(token.Value);
                break;
        }
    }

    return output.ToString();
}

Nuansa berikutnya dalam konversi adalah penggunaan konstanta Excel - mereka adalah fungsi, jadi dalam C # mereka juga harus dibungkus dalam suatu fungsi. 

Tetap hanya menyelesaikan satu pertanyaan: konversi referensi sel ke parameter. Dalam kasus di mana token berisi informasi tentang sel, pertama-tama kita menentukan apa yang disimpan dalam sel ini. Jika ini adalah rumus, perluas itu secara rekursif. Jika konstanta diganti dengan tautan analisis C #, dari formulir p[row, column], di mana ia pbisa berupa array dua dimensi atau kelas akses yang diindeks untuk pemetaan data yang benar. Dengan rentang sel, kami melakukan hal yang sama, hanya memperluas rentang menjadi sel-sel individual dan memprosesnya secara terpisah. Jadi, kami membahas fungsionalitas utama saat menerjemahkan fungsi Excel. 


Di bawah ini adalah kode untuk mengonversi tautan ke sel spreadsheet Excel menjadi kode C # yang valid:

private string TransformAddressToSharpCode(string excelAddress, ParsingContext parsingContext, ParsingScope scope, ILexer lexer, Dictionary<string, string> variables)
{
    // Try to parse excel range of addresses
    // Currently, reference to another worksheet in address string is not supported

    var rangeParts = excelAddress.Split(':');
    if (rangeParts.Length == 1)
    {
        // Unpack single excel address
        return UnpackExcelAddress(excelAddress, parsingContext, scope, lexer, variables);
    }

    // Parse excel range address
    ParseAddressToIndexes(rangeParts[0], out int startRowIndex, out int startColumnIndex);
    ParseAddressToIndexes(rangeParts[1], out int endRowIndex, out int endColumnIndex);

    var rowDelta = endRowIndex - startRowIndex;
    var columnDelta = endColumnIndex - startColumnIndex;

    var allAccessors = new List<string>(Math.Abs(rowDelta * columnDelta));

    // TODO This part of code doesn't support reverse-ordered range address
    for (var rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++)
    {
        for (var columnIndex = startColumnIndex; columnIndex <= endColumnIndex; columnIndex++)
        {
            // Unpack single excel address
            allAccessors.Add(UnpackExcelAddress(rowIndex, columnIndex, parsingContext, scope, lexer, variables));
        }
    }

    return string.Join(", ", allAccessors);
}

private string UnpackExcelAddress(string excelAddress, ParsingContext parsingContext, ParsingScope scope, ILexer lexer, Dictionary<string, string> variables)
{
    ParseAddressToIndexes(excelAddress, out int rowIndex, out int columnIndex);
    return UnpackExcelAddress(rowIndex, columnIndex, parsingContext, scope, lexer, variables);
}

private string UnpackExcelAddress(int rowIndex, int columnIndex, ParsingContext parsingContext, ParsingScope scope, ILexer lexer, Dictionary<string, string> variables)
{
    var formula = parsingContext.ExcelDataProvider.GetRangeFormula(_worksheet.Name, rowIndex, columnIndex);
    if (string.IsNullOrWhiteSpace(formula))
    {
        // When excel address doesn't contain information about any excel formula, we should just use external input data parameter provider.
        return $"p[{rowIndex},{columnIndex}]";
    }

    // When formula is provided, try to identify that variable is not defined yet
    // TODO Worksheet name is not included in variable name, potentially that can cause conflicts
    // Extracting and reusing calculations via local variables improves performance for 0.0045ms
    var cellVariableId = $"C{rowIndex}R{columnIndex}";
    if (variables.ContainsKey(cellVariableId))
    {
        return cellVariableId;
    }

    // When variable does not exist, transform new formula and register that to variable scope
    variables.Add(cellVariableId, TransformToSharpCode(formula, parsingContext, scope, lexer, variables));

    return cellVariableId;
}

Tetap hanya untuk membungkus kode yang dikonversi yang dihasilkan menjadi fungsi statis, menghubungkan perakitan dengan fungsi kompatibilitas, dan mengkompilasi perakitan dinamis. Masukkan ke dalam memori, dapatkan tautan ke fungsi kami - dan Anda dapat menggunakannya. 

Kami menulis kelas pembungkus untuk menguji dan menjalankan tes dengan pengukuran waktu. 

public void SetUp()
{
    // Initialize excel package by EPPlus library
    _package = new ExcelPackage(new FileInfo(_fileName));
    _workbook = _package.Workbook;
    _worksheet = _workbook.Worksheets[1];

    _inputRange = new ExcelRange[10];
    for (int rowIndex = 0; rowIndex < 10; rowIndex++)
    {
        _inputRange[rowIndex] = _worksheet.Cells[rowIndex + 1, 2];
    }

    // Access to result cell and extract formula string
    _resultRange = _worksheet.Cells[11, 2];

    var formula = _resultRange.Formula;

    // Initialize parsing context and setup data provider
    var parsingContext = ParsingContext.Create();
    parsingContext.ExcelDataProvider = new EpplusExcelDataProvider(_package);

    // Transform Excel formula to CSharp code
    var sourceCode = TransformToSharpCode(formula, parsingContext);

    // Compile CSharp code to IL dynamic assembly via helper wrappers
    _code = CodeGenerator.CreateCode<double>(
        sourceCode,
        new string[]
        {
            // List of used namespaces
            "System", // Required for Math functions
            "ExcelCalculations.PerformanceTests" // Required for Excel function wrappers stored at ExcelCompiledFunctions static class
        },
        new string[]
        {
            // Add reference to current compiled assembly, that is required to use Excel function wrappers located at ExcelCompiledFunctions static class
            "....\\bin\\Debug\\ExcelCalculations.PerformanceTests.exe"
        },
        // Notify that this source code should use parameter;
        // Use abstract p parameter - interface for values accessing.
        new CodeParameter("p", typeof(IExcelValueProvider))
    );
}

Hasilnya, kami memiliki prototipe solusi ini dan menandainya sebagai EPPlusCompiled, Mark-I . Setelah menjalankan tes, kami mendapatkan hasil yang lama ditunggu-tunggu. Akselerasinya hampir 300 kali. Sudah tidak buruk, tetapi kode yang dihasilkan masih 16 kali lebih lambat dari yang asli. Mungkinkah ini lebih baik?

Ya kamu bisa! Mari kita coba untuk meningkatkan hasilnya karena kita akan mengganti semua tautan ke sel tambahan dengan rumus dengan variabel. Pengujian kami menggunakan beberapa penggunaan sel dependen dalam rumus, oleh karena itu, dalam versi pertama penerjemah, kami menerima banyak perhitungan dari data yang sama. Oleh karena itu, diputuskan untuk menggunakan variabel perantara dalam perhitungan. Setelah memperluas kode menggunakan generasi variabel dependen, kami mendapat peningkatan kinerja 2 kali lebih banyak. Perbaikan ini disebutEPPlusCompiled, Mark-II . Tabel perbandingan disajikan di bawah ini:

PerpustakaanMengawinkan waktu (ms)Coef. perlambatan
Asli0,000041
EPPlusCompiled, Mark-II0,0038
EPPlusCompiled, Mark-I0,0061enambelas
EPPlus1,20893023

Di bawah kondisi ini dan batas waktu yang diberikan untuk tugas tersebut, kami mendapat hasil yang membawa kami lebih dekat dengan kinerja kode asli dengan sedikit lag - 8 kali, dibandingkan dengan versi asli - lag dari beberapa urutan besarnya, 3028 kali. Tetapi apakah mungkin untuk meningkatkan hasilnya dan mendapatkan sedekat mungkin dengan kode asli, jika Anda menghapus batas waktu dan seberapa sesuai?

Jawaban saya adalah ya, tetapi, sayangnya, saya tidak lagi punya waktu untuk menerapkan teknik ini. Mungkin saya akan mencurahkan artikel terpisah untuk topik ini. Saat ini, saya hanya dapat berbicara tentang ide dan opsi utama, menuliskannya dalam bentuk abstrak singkat yang telah diverifikasi oleh transformasi terbalik. Dengan konversi terbalik, maksud saya degradasi kode asli yang ditulis dengan tangan ke arah kode yang dihasilkan. Pendekatan ini memungkinkan Anda untuk memeriksa beberapa tesis dengan cukup cepat dan tidak memerlukan perubahan signifikan dalam kode. Ini juga memungkinkan Anda untuk menjawab pertanyaan tentang bagaimana kinerja kode asli akan memburuk dalam kondisi tertentu, yang berarti bahwa jika kode yang dihasilkan ditingkatkan secara otomatis di arah yang berlawanan, kita bisa mendapatkan peningkatan kinerja dengan koefisien yang sama.

Abstrak


  1. , ;
  2. inline ;
  3. - Sum, Max, Min ;
  4. Sum inline ;
  5. ( ) .


NativeEPPlus Compiled, Mark-IIEPPlus 4EPPlus 5NPOISpireExcel Interop
()02392413687221640
. 1 ()0,00040,0030,91741,89967,764750.7194
Rata-rata deviasi0,0358840,00,00,00,0t / a
Ketepatan98,79%100,0%100,0%100,0%100,0%t / a
Kesalahan0,0%0,0%0,3%0,3%0,28%0,3%

Perhitungan cepat rumus dari Excel dalam C #

Ringkas langkah-langkahnya, kami memiliki mekanisme untuk mengubah formula langsung dari dokumen Excel kustom menjadi kode yang berfungsi di server. Ini memungkinkan Anda untuk menggunakan fleksibilitas yang luar biasa dari pengintegrasian Excel dengan solusi bisnis apa pun tanpa kehilangan antarmuka pengguna yang kuat yang digunakan oleh banyak pengguna. Apakah mungkin untuk mengembangkan antarmuka yang nyaman dengan seperangkat alat yang sama untuk menganalisis dan memvisualisasikan data seperti di Excel untuk periode pengembangan yang begitu singkat?

Dan integrasi apa yang paling tidak biasa dan menarik dengan dokumen Excel yang harus Anda implementasikan?

All Articles