Thư viện toán độ chính xác tùy ý đa nền tảng (di động) tốt nhất là gì? [đóng cửa]


81

Tôi đang tìm kiếm một thư viện toán học chính xác tùy ý tốt trong C hoặc C ++. Bạn có thể vui lòng cho tôi một số lời khuyên hoặc đề xuất?

Các yêu cầu chính:

  1. phải xử lý các số nguyên lớn tùy ý — mối quan tâm chính của tôi là trên các số nguyên. Trong trường hợp bạn không biết từ lớn có nghĩa là gì, hãy tưởng tượng một cái gì đó giống như 100000! (giai thừa của 100000).

  2. Độ chính xác không cần phải được chỉ định trong quá trình khởi tạo thư viện hoặc tạo đối tượng. Độ chính xác chỉ nên bị hạn chế bởi các tài nguyên có sẵn của hệ thống.

  3. sẽ sử dụng toàn bộ sức mạnh của nền tảng và nên xử lý các số lượng "nhỏ" một cách nguyên bản. Điều đó có nghĩa là trên nền tảng 64 bit, việc tính toán (2 ^ 33 + 2 ^ 32) nên sử dụng các hướng dẫn sẵn có của CPU 64 bit. Thư viện không nên tính toán điều này theo cách tương tự như nó làm với (2 ^ 66 + 2 ^ 65) trên cùng một nền tảng.

  4. phải xử lý hiệu quả các phép tính cộng ( +), trừ ( -), nhân ( *), chia số nguyên ( /), phần dư %( **), lũy thừa ( ), tăng ( ++), giảm ( --), GCD, giai thừa và các phép tính số học số nguyên phổ biến khác. Khả năng xử lý các hàm như căn bậc hai và logarit không tạo ra kết quả số nguyên là một điểm cộng. Khả năng xử lý các phép tính tượng trưng thậm chí còn tốt hơn.

Đây là những gì tôi tìm thấy cho đến nay:

  1. Lớp BigIntegerBigDecimal của Java : Tôi đã sử dụng chúng cho đến nay. Tôi đã đọc mã nguồn, nhưng tôi không hiểu toán học bên dưới. Nó có thể dựa trên những lý thuyết và thuật toán mà tôi chưa từng học.

  2. Kiểu số nguyên tích hợp sẵn hoặc trong các thư viện lõi của bc , Python , Ruby , Haskell , Lisp , Erlang , OCaml , PHP , một số ngôn ngữ khác: Tôi đã sử dụng một số ngôn ngữ này, nhưng tôi không biết họ đang sử dụng thư viện nào, hoặc họ đang sử dụng loại triển khai nào.

Những gì tôi đã biết:

  1. Sử dụng charcho các chữ số thập phân và char*cho các chuỗi thập phân, và thực hiện các phép tính trên các chữ số bằng cách sử dụng dấu for-loop.

  2. Sử dụng int(hoặc long int, hoặc long long) làm “đơn vị” cơ bản và một mảng thuộc loại đó dưới dạng số nguyên dài tùy ý và thực hiện các phép tính trên các phần tử bằng cách sử dụng for-loop.

  3. Sử dụng kiểu số nguyên để lưu trữ một chữ số thập phân (hoặc một vài chữ số) dưới dạng BCD (Số thập phân được mã hóa nhị phân) .

  4. Thuật toán nhân của Booth .

Những gì tôi không biết:

  1. In mảng nhị phân được đề cập ở trên dưới dạng thập phân mà không sử dụng các phương pháp ngây thơ. Một ví dụ về phương pháp ngây thơ: (1) cộng các bit từ thấp nhất đến cao nhất: 1, 2, 4, 8, 16, 32,… (2) sử dụng chuỗi a char*đã đề cập ở trên để lưu trữ các kết quả thập phân trung gian).

Điều tôi đánh giá cao:

  1. So sánh tốt về GMP , MPFR , decNumber (hoặc các thư viện khác tốt theo ý kiến ​​của bạn).

  2. Những gợi ý hay về những cuốn sách và bài báo mà tôi nên đọc. Ví dụ: một minh họa với các số liệu về cách hoạt động của thuật toán chuyển đổi nhị phân sang thập phân không ngây thơ sẽ rất tốt. Bài báo “ Chuyển đổi từ nhị phân sang thập phân trong độ chính xác có hạn ” của Douglas W. Jones là một ví dụ về một bài báo hay.

  3. Mọi sự giúp đỡ nói chung.

Vui lòng không trả lời câu hỏi này nếu bạn nghĩ rằng việc sử dụng double(hoặc long double, hoặc long long double) có thể giải quyết vấn đề này một cách dễ dàng. Nếu bạn nghĩ như vậy, bạn không hiểu vấn đề được đề cập.


3
Theo như tôi thấy, GMP có vẻ là một thư viện tốt. Điều tôi thắc mắc là tại sao lại cần những người đóng góp Python / Haskell / Erlang / etc để phát minh lại bánh xe. Nếu GMP là tốt như vậy, tại sao không dựa vào nó? Giấy phép GPL / LGPL có thể là một trong những vấn đề, nhưng bất chấp điều này (và cả vấn đề chế độ làm tròn), có bất kỳ nhược điểm nào khác của GMP không? Số nguyên tích hợp sẵn của Python / Haskell / Erlang / bất kỳ thư viện mật mã nào nhanh hơn GMP? Nếu có, tôi xin phép trích xuất và sử dụng nó, nếu giấy phép cho phép.
Siu Ching Pong -Asuka Kenji-

Tôi tìm thấy một bài báo hay tại cs.uiowa.edu/~jones/bcd/decimal.html của Douglas W. Jones. Bài viết mô tả một phương pháp để chuyển đổi một số nguyên 16 bit thành biểu diễn thập phân chỉ sử dụng số học số nguyên 8 bit. Ý tưởng là chia số 16 bit thành 4 ngòi, mỗi ngòi đại diện cho một "chữ số" cơ số 16. Vì vậy, chữ số-0 (n0) đại diện cho x1, n1 => x16, n2 => x256, n3 => x4096. Khi đó, rõ ràng chữ số-0 của số thập phân (d0) là chữ số-0 trong kết quả của n0 * 1 + n1 * 6 + n2 * 6 + n3 * 6. Bằng cách xử lý mang đúng cách, từ d1 đến d4 có thể cũng được tính toán.
Siu Ching Pong -Asuka Kenji-

Tuy nhiên, theo như tôi có thể tưởng tượng, ý tưởng của Douglas ở trên không thể được mở rộng để xử lý các số nguyên nhị phân dài tùy ý. Đó là vì các số 1 (16 ^ 0), 16 (16 ^ 1), 256 (16 ^ 2) và 4096 (16 ^ 3) được tính toán trước. Sau đó, vấn đề trở thành cách biểu diễn 16 ^ n dưới dạng thập phân cho n lớn tùy ý.
Siu Ching Pong -Asuka Kenji-

Câu trả lời:


24

GMP là sự lựa chọn phổ biến. Squeak Smalltalk có một thư viện rất đẹp, nhưng nó được viết bằng Smalltalk.

Bạn đã yêu cầu những cuốn sách hoặc bài báo có liên quan. Phần khó khăn của bignums là sự phân chia dài. Tôi giới thiệu bài báo của Per Brinch Hansen, Bộ phận có nhiều độ dài đã được xem lại: Chuyến tham quan bãi mìn .


Cảm ơn bạn đã liên kết đến bài báo! Vâng, tôi đồng ý rằng phân chia là phần khó khăn nhất. Tôi đã biết cách thực hiện phép chia bằng tay bằng cách sử dụng "phương pháp giấy và bút chì" từ lâu :-) và do đó, phương pháp tương tự có thể được áp dụng cho chuỗi thập phân của char *(mỗi chuỗi charđại diện cho một chữ số thập phân) hoặc int *chuỗi BCD ( mỗi intđại diện cho 4/8/16 chữ số BCD). Tuy nhiên, tôi tự hỏi liệu các thư viện cấp sản xuất trong thế giới thực có bắt chước "phương pháp giấy và bút chì" hay không, vì nó quá chậm.
Siu Ching Pong -Asuka Kenji-

Để xem tại sao, chúng ta hãy tưởng tượng nó chạy như thế nào 100,000,000,000,000,000 / 333,333,333,333: Bước đầu tiên là so sánh 100,000,000,000với 333,333,333,333. Vì số trước nhỏ hơn số sau nên phép tính chỉ đơn giản là chuyển sang chữ số tiếp theo. Bước thứ hai là tìm thương số của 1,000,000,000,000 / 333,333,333,333, điều này liên quan đến phép nhân thử và sai của 333,333,333,333 * 1(và * 2, * 3* 4) hoặc thực hiện các phép trừ liên tiếp trong một vòng lặp. Bạn có thấy nó chậm như thế nào không? Tôi tin rằng các thuật toán hiệu quả hơn tồn tại.
Siu Ching Pong -Asuka Kenji-

3
@Sui: Brinch Hanson chỉ ra cách bạn có thể giảm phương pháp thử-và-sai xuống tối đa hai lần thử. Nó thực sự rất ấn tượng.
Norman Ramsey

Được rồi, hãy để tôi xem xét chi tiết hơn về bài báo. Cảm ơn bạn!
Siu Ching Pong -Asuka Kenji-

1
Tôi không chắc bạn đã tìm ra giải pháp của mình ở đâu, cũng như định dạng bạn đã sử dụng để lưu trữ các chữ số, nhưng định dạng nybble COMP-3 của COBOL dễ giải quyết hơn rất nhiều, vì nó nhỏ gọn hơn, mỗi 4 bit lưu trữ một 0-9 giá trị, VÀ, bạn không bắt buộc phải trừ hex 30 từ giá trị ký tự ASCII để nhận được một chữ số có thể sử dụng được.

13

Nhìn chung, thư viện chính xác tùy ý mục đích chung nhanh nhất là GMP . Nếu bạn muốn làm việc với các giá trị dấu phẩy động, hãy xem thư viện MPFR . MPFR dựa trên GMP.

Về hỗ trợ độ chính xác tùy ý tự nhiên trong các ngôn ngữ khác, Python sử dụng triển khai riêng của nó vì lý do giấy phép, kích thước mã và tính khả chuyển của mã. Các GMPY mô-đun cho phép truy cập thư viện Python GMP.


Cảm ơn bạn đã phản hồi! Bạn đã đề cập đến "tính di động của mã". Bạn có thể vui lòng giải thích vấn đề là gì? Tôi nghĩ rằng GMP là có thể di động và được hỗ trợ trên các nền tảng lớn ...
Siu Ching Pong -Asuka Kenji-

2
"tính khả chuyển của mã" không giống như "được hỗ trợ trên các nền tảng chính". Python sử dụng một triển khai đơn giản tạo ra rất ít giả định về hành vi của trình biên dịch C, do đó, cùng một đoạn mã có thể biên dịch trên hầu hết mọi trình biên dịch C. GMP sử dụng nhiều mã hơn (C và lắp ráp được điều chỉnh cao) làm cho GMP nhanh hơn nhưng cũng đưa ra nhiều giả định hơn về hoạt động của trình biên dịch và trình biên dịch C. Ví dụ: GMP không được hỗ trợ tốt bởi trình biên dịch Microsoft Visual Studio. Có một nhánh GMP gọi là MPIR (www.mpir.org) hỗ trợ các trình biên dịch của Microsoft.
casevh

Tôi hiểu rồi. Điều đó có nghĩa là triển khai Python giống ANSI C hơn trong khi triển khai GMP sử dụng thủ thuật __asm ​​... Cảm ơn bạn đã giải thích.
Siu Ching Pong -Asuka Kenji-

8

Xem TTMath , một thư viện nhỏ chỉ dành cho tiêu đề mẫu, miễn phí cho mục đích sử dụng cá nhân và thương mại.


Chào! Đây là một thư viện dễ sử dụng và có vẻ như nó sử dụng sức mạnh của CPU và nó sử dụng một số phép thuật mẫu C ++ để hoàn thành công việc. Thư viện tuyệt vời! +1 cho bạn!
Siu Ching Pong -Asuka Kenji-

Vâng, và nó có giấy phép BSD không copyleft được phép.
plasmacel

Từ trang trên: "Giá trị có thể được đặt lớn như thế nào tại thời điểm biên dịch." - vì vậy điều này không phù hợp với yêu cầu.
osxdirk

7

Bản thân tôi đã không so sánh các thư viện số học chính xác tùy ý với nhau, nhưng những người dường như đã giải quyết một cách thống nhất về GMP. Đối với những gì nó đáng giá, các số nguyên chính xác tùy ý trong GHC Haskell và GNU Guile Scheme đều được thực hiện bằng cách sử dụng GMP và việc triển khai nhanh nhất tiêu chuẩn pidigits trên loạt đấu súng ngôn ngữ dựa trên GMP.


Cảm ơn! ^ ___ ^ Thông tin tốt đẹp!
Siu Ching Pong -Asuka Kenji-

4

Còn Pari thì sao? Nó được xây dựng dựa trên GMP hàng đầu và cung cấp tất cả các tiện ích khác về các phép toán lý thuyết số mà bạn sẽ cần (và nhiều công cụ tính toán tượng trưng).


Chào fortran (!), Có vẻ ổn! Cảm ơn vì thông tin của bạn!
Siu Ching Pong -Asuka Kenji-

Bạn được chào đón :-) Ngoài ra với Pari, bạn có thể cuộn các nguyên mẫu nhanh bằng GP và khi bạn hài lòng, hãy viết phiên bản C được tối ưu hóa (và tôi nghĩ nó đi kèm với trình biên dịch GP-> C để trợ giúp điều đó)
fortran
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.