• Stars
    star
    127
  • Rank 282,790 (Top 6 %)
  • Language
    C#
  • License
    MIT License
  • Created almost 2 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A modern .NET library that can PInvoke to gmp and mpfr, that enable both high performance and best .NET convenience.

Sdcb.Arithmetic main QQ

Sdcb.Arithmetic is a modern .NET library that can PInvoke to gmp and mpfr, that enable both high performance and best .NET convenience.

Known classes in Sdcb.Arithmetic:

Class Native name Library
GmpInteger mpz_t Sdcb.Arithmetic.Gmp
GmpFloat mpf_t Sdcb.Arithmetic.Gmp
GmpRational mpq_t Sdcb.Arithmetic.Gmp
GmpRandom gmp_randstate_t Sdcb.Arithmetic.Gmp
MpfrFloat mpfr_t Sdcb.Arithmetic.Mpfr

NuGet Packages

libgmp

Package Id Version License Notes
Sdcb.Arithmetic.Gmp NuGet MIT .NET binding for libgmp
Sdcb.Arithmetic.Gmp.runtime.win64 NuGet LGPL native lib in windows x64
Sdcb.Arithmetic.Gmp.runtime.win32 NuGet LGPL native lib in windows x86
Sdcb.Arithmetic.Gmp.runtime.linux64 NuGet LGPL native lib in Linux x64

mpfr

Package Id Version License Notes
Sdcb.Arithmetic.Mpfr NuGet MIT .NET binding for libmpfr
Sdcb.Arithmetic.Mpfr.runtime.win64 NuGet LGPL native lib in windows x64
Sdcb.Arithmetic.Mpfr.runtime.win32 NuGet LGPL native lib in windows x86
Sdcb.Arithmetic.Mpfr.runtime.linux64 NuGet LGPL native lib in linux x64

Question - Why not linux-64 can't run in my linux?

The linux-x64 package is compiled using vcpkg in Ubuntu 22.04, so it may not run in other linux distributions.

If you want to run in other linux distributions, you can compile it yourself, or install it using apt or yum or other package manager.

This is the all native dynamic library name in case you wondering(defined in GmpNativeLoader.cs and MpfrNativeLoader.cs):

OS gmp dynamic lib mpfr dynamic lib
Windows gmp-10.dll mpfr-6.dll
Linux libgmp.so.10 libmpfr.so.6
MacOS libgmp.10.dylib libmpfr.6.dylib
Others gmp.10 mpfr.6

Examples

Calculate 1,000,000 length of π using Sdcb.Arithmetic.Gmp:

// Install NuGet package: Sdcb.Arithmetic.Gmp
// Install NuGet package: Sdcb.Arithmetic.Gmp.runtime.win-x64(for windows)
using Sdcb.Arithmetic.Gmp;

Console.WriteLine(CalcPI().ToString("N1000000"));

GmpFloat CalcPI(int inputDigits = 1_000_000)
{
    const double DIGITS_PER_TERM = 14.1816474627254776555; // = log(53360^3) / log(10)
    int DIGITS = (int)Math.Max(inputDigits, Math.Ceiling(DIGITS_PER_TERM));
    uint PREC = (uint)(DIGITS * Math.Log2(10));
    int N = (int)(DIGITS / DIGITS_PER_TERM);
    const int A = 13591409;
    const int B = 545140134;
    const int C = 640320;
    const int D = 426880;
    const int E = 10005;
    const double E3_24 = (double)C * C * C / 24;

    using PQT pqt = ComputePQT(0, N);

    GmpFloat pi = new(precision: PREC);
    // pi = D * sqrt((mpf_class)E) * PQT.Q;
    pi.Assign(GmpFloat.From(D, PREC) * GmpFloat.Sqrt((GmpFloat)E, PREC) * (GmpFloat)pqt.Q);
    // pi /= (A * PQT.Q + PQT.T);
    GmpFloat.DivideInplace(pi, pi, GmpFloat.From(A * pqt.Q + pqt.T, PREC));
    return pi;

    PQT ComputePQT(int n1, int n2)
    {
        int m;

        if (n1 + 1 == n2)
        {
            PQT res = new()
            {
                P = GmpInteger.From(2 * n2 - 1)
            };
            GmpInteger.MultiplyInplace(res.P, res.P, 6 * n2 - 1);
            GmpInteger.MultiplyInplace(res.P, res.P, 6 * n2 - 5);

            GmpInteger q = GmpInteger.From(E3_24);
            GmpInteger.MultiplyInplace(q, q, n2);
            GmpInteger.MultiplyInplace(q, q, n2);
            GmpInteger.MultiplyInplace(q, q, n2);
            res.Q = q;

            GmpInteger t = GmpInteger.From(B);
            GmpInteger.MultiplyInplace(t, t, n2);
            GmpInteger.AddInplace(t, t, A);
            GmpInteger.MultiplyInplace(t, t, res.P);
            // res.T = (A + B * n2) * res.P;            
            if ((n2 & 1) == 1) GmpInteger.NegateInplace(t, t);
            res.T = t;

            return res;
        }
        else
        {
            m = (n1 + n2) / 2;
            PQT res1 = ComputePQT(n1, m);
            using PQT res2 = ComputePQT(m, n2);
            GmpInteger p = res1.P * res2.P;
            GmpInteger q = res1.Q * res2.Q;

            // t = res1.T * res2.Q + res1.P * res2.T
            GmpInteger.MultiplyInplace(res1.T, res1.T, res2.Q);
            GmpInteger.MultiplyInplace(res1.P, res1.P, res2.T);
            GmpInteger.AddInplace(res1.T, res1.T, res1.P);
            res1.P.Dispose();
            res1.Q.Dispose();
            return new PQT
            {
                P = p,
                Q = q,
                T = res1.T,
            };
        }
    }
}

public ref struct PQT
{
    public GmpInteger P;
    public GmpInteger Q;
    public GmpInteger T;

    public readonly void Dispose()
    {
        P?.Dispose();
        Q?.Dispose();
        T?.Dispose();
    }
}

Technical notes

Why choosing struct in class design instead of raw memory IntPtr design?

  • (1) Struct in class design:

    class GmpInteger
    {
      public readonly Mpz_t Raw;
    
      public unsafe void DoWork()
      {
          fixed (Mpz_t* ptr = &Raw)
          {
              GmpLib.__dowork((IntPtr)ptr);
          }
      }
    }
    
    struct Mpz_t
    {
      public int A, B;
      public IntPtr Limbs;
    }
  • (2) Raw memory IntPtr design:

    class GmpInteger : IDisposable
    {
      public readonly IntPtr Raw;
    
      public unsafe GmpInteger()
      {
          Raw = Marshal.AllocHGlobal(sizeof(Mpz_t));
      }
    
      public void DoWork()
      {
          GmpLib.__dowork(Raw);
      }
    
      public void Dispose()
      {
          Marshal.FreeHGlobal(Raw);
      }
    }

    Here is some benchmark I tested for both DoWork senario and initialize-dispose senario:

    Details:

    • init & dispose combines following actions:
      • allocating struct memory
      • calling mpz_init
      • calling mpz_free
      • free the memory
      • Measure the operations-per-seconds, higher ops is better
    • dowork contains following actions:
      • create a GmpFloat to 1.5 with precision=1000(v = 1, a = 1.5)
      • Calling MultiplyInplace(v *= a) 10*1024*1024 times
      • Measure the duration, lower is better

    Here is the tested results in my laptop:

    case/senario init & dispose dowork
    Struct in class 82,055,792 ops 1237ms
    Raw memory IntPtr 15,543,619 ops 1134ms

    As you can see, raw memory IntPtr design will benifits ~8.33% faster in dowork senario above, but struct in class design will be 5.2x faster in init & dispose senario.

    Finally I choosed the struct in class design, here is some existing Raw memory IntPtr design work if you also wants to check or test:

    Struct in class performance results environment:

    In the future, Raw memory IntPtr design can be pick-up if a handy, good performance memory allocator was found.

More Repositories

1

PaddleSharp

.NET/C# binding for Baidu paddle inference library and PaddleOCR
C#
1,027
star
2

OpenVINO.NET

High quality .NET wrapper for OpenVINO™ toolkit.
C#
360
star
3

Sdcb.FFmpeg

FFmpeg basic .NET API generated by CppSharp
C#
323
star
4

sdmap

A template engine for writing dynamic sql.
C#
96
star
5

blog-data

《.NET骚操作》的博客数据
C#
78
star
6

Sdcb.WordCloud

Generate WordCloud image from .NET/.NET Core
C#
72
star
7

Sdcb.LibRaw

Advanced raw image processing library in C# based on LibRaw.
C#
69
star
8

Sdcb.DashScope

为阿里云灵积模型服务DashScope开发的非官方.NET SDK
C#
66
star
9

Sdcb.SparkDesk

讯飞星火大模型非官方.NET SDK Xunfei's "Xinghuo" SparkDesk large model unofficial sdk for .NET
C#
64
star
10

FlysEngine

Real-time 2D rendering utilities based on Vortice.Windows/Direct2D.
C#
50
star
11

blade

旋刃竞技场
JavaScript
39
star
12

mini-openvino-paddleocr

Simple Sdcb.OpenVINO demo for PaddleOCR
C#
31
star
13

Sdcb.ScreenCapture

C#
31
star
14

dotnet-cv2021

2021 .NET Conf China 《.NET玩转计算机视觉OpenCV》 源代码仓库 (周杰)
C#
26
star
15

2019-ncp-simulation

C#
20
star
16

sdcb-openvino-yolov8-det

Sdcb.OpenVINO demo project to infer yolov8 detection model
C#
19
star
17

Sdcb.StabilityAI

Unofficial Stability AI rest API C# SDK
C#
19
star
18

sorry

Create wjz/sorry gif by ASP.NET Core & Sdcb.FFmpeg
C#
18
star
19

Sdcb.Imaging

Direct2D based watermark/captcha tool.
C#
14
star
20

dx

A modern C++ library for DirectX programming
C++
14
star
21

opencvsharp-mini-runtime

mini runtime that suitable for model inference in server.
14
star
22

sdcb-openvino-yolov8-cls

Demo for Sdcb.OpenVINO project to infer yolov8 cls model
C#
13
star
23

mini-openvino-facedetection

A mini face detection demo using OpenVINO.NET
C#
12
star
24

Sdcb.WenXinQianFan

百度文心千帆平台非官方.NET SDK
C#
12
star
25

Sdcb.FFmpegAPIWrapper

.NET FFmpeg API Warpper Library.
C#
10
star
26

paddleocr-demo

PaddleSharp OCR ASP.NET Core demo
C#
10
star
27

Sdcb.PictureSpeaks

画中有话·基于azure chatgpt和dalle3的猜成语app
C#
9
star
28

TypeScriptAST

TypeScript AST Parser, .NET Core standard 2.0 library, forked from: https://github.com/ToCSharp/TypeScriptAST
C#
7
star
29

Ecd2Pem

Convert .NET ECD CngKey/key pair into PEM file.
C#
5
star
30

dotnetconf-changsha-20240225

C#
5
star
31

Sdcb.System.Range

Provide System.Index, System.Range for C# 8.0.
C#
3
star
32

Sdcb.Mattermost.DotNetSdk

.NET SDK for Mattermost
C#
3
star
33

Antlr4Test

C#
2
star
34

TellyouMsdn

对msdn.itellyou.cn的C#爬虫
C#
2
star
35

GPTCodingAssistant

TypeScript
2
star
36

sdlife

Life related tools for sdcb.
C#
1
star
37

YeluCasSsoClient

One line code to integrate your Yelu CAS SSO
C#
1
star
38

ibatis2sdmap

Migrate iBatis xml to sdmap script.
C#
1
star
39

MFPL

My First Programming Language
C#
1
star
40

sdsky

TypeScript
1
star
41

Sdcb.Collections

Useful collections by sdcb.
C#
1
star
42

2048

Another 2048 game for mobile device.
TypeScript
1
star
43

RtPaint

Real-time paint tool for presentation.
JavaScript
1
star