Khi nào phải sử dụng các hàm số học chính xác tùy ý trong PHP?


8

Đồng nghiệp của tôi sử dụng các chức năng Máy tính nhị phân trong tính toán băng thông; nhiều như terrabyte, và với tỷ lệ phần trăm phân chia trên phân bổ. Việc sử dụng các hàm này của anh ta có vẻ đúng để không bị mất một byte; mặc dù anh ấy dường như đang sử dụng chúng cho mọi thứ

Hướng dẫn chỉ nói:

Đối với toán học chính xác tùy ý, PHP cung cấp Máy tính nhị phân hỗ trợ các số có kích thước và độ chính xác bất kỳ, được biểu diễn dưới dạng chuỗi.

Bao nhiêu là kích thước? Có thực sự cần thiết? Làm thế nào lớn là float nổi mặc định trong PHP? Có lời khuyên tốt nào liên quan đến điều này hoặc những điều cần ghi nhớ?

Câu trả lời:


13

Kích thước của số nguyên trong PHP phụ thuộc vào nền tảng .

Kích thước của một số nguyên phụ thuộc vào nền tảng, mặc dù giá trị tối đa khoảng hai tỷ là giá trị thông thường (đó là 32 bit được ký). Các nền tảng 64 bit thường có giá trị tối đa khoảng 9E18. PHP không hỗ trợ số nguyên không dấu. Kích thước số nguyên có thể được xác định bằng cách sử dụng hằng số PHP_INT_SIZE và giá trị tối đa bằng cách sử dụng hằng số PHP_INT_MAX kể từ PHP 4.4.0 và PHP 5.0.5.

Kích thước của phao, cũng phụ thuộc vào nền tảng :

Kích thước của một float là phụ thuộc vào nền tảng, mặc dù tối đa ~ 1,8e308 với độ chính xác khoảng 14 chữ số thập phân là một giá trị phổ biến (định dạng IEEE 64 bit).

và có một cảnh báo lớn màu đỏ trong hướng dẫn về độ chính xác của phao:

Số dấu phẩy động có độ chính xác hạn chế. Mặc dù phụ thuộc vào hệ thống, PHP thường sử dụng định dạng chính xác kép của IEEE 754, điều này sẽ gây ra lỗi tương đối tối đa do làm tròn theo thứ tự 1.11e-16. Các phép toán số học không phải là số học cơ bản có thể cho các lỗi lớn hơn và tất nhiên, việc xem xét lỗi phải được xem xét khi một số phép toán được gộp.

Ngoài ra, các số hữu tỷ có thể biểu diễn chính xác như các số dấu phẩy động trong cơ sở 10, như 0,1 hoặc 0,7, không có biểu diễn chính xác như các số dấu phẩy động trong cơ sở 2, được sử dụng bên trong, bất kể kích thước của lớp phủ. Do đó, chúng không thể được chuyển đổi thành các đối tác nhị phân nội bộ của chúng mà không mất một chút chính xác. Điều này có thể dẫn đến kết quả khó hiểu: ví dụ: sàn ((0,1 + 0,7) * 10) thường sẽ trả về 7 thay vì 8 như mong đợi, vì đại diện bên trong sẽ giống như 7.999999999999999991118 ....

Phần mở rộng BC Math bỏ qua các phụ thuộc, cho phép bạn chỉ định rõ ràng một số nguyên lớn dưới dạng một chuỗi và tránh việc diễn giải các số nguyên của PHP. Các chức năng GMP cũng là lựa chọn thay thế tốt và hoạt động theo cách tương tự. Chúng ta có thể giả định một cách an toàn any sizeđề cập đến kích thước tối đa của chuỗi, chỉ bị giới hạn bởi bộ nhớ khả dụng :

Không có vấn đề gì khi một chuỗi trở nên rất lớn. PHP áp đặt không có ranh giới về kích thước của một chuỗi; giới hạn duy nhất là bộ nhớ khả dụng của máy tính mà PHP đang chạy.

Cho dù nó có ý nghĩa hay không chỉ có thể được quyết định trên cơ sở từng trường hợp. Tôi chưa bao giờ nhận thấy bất kỳ vấn đề hiệu suất thực tế nào với các chức năng của tiện ích mở rộng, nhưng chắc chắn là chúng không nhanh như các lựa chọn thay thế.


Có thực sự cần thiết?

Nó chỉ cần thiết khi nó là, nhưng điều đó không phải lúc nào cũng rõ ràng. Bạn có thể dễ dàng xác định lạm dụng trắng trợn, nhưng không thể dễ dàng tranh luận về các tình huống phức tạp hơn.

Thảo luận với đồng nghiệp của bạn và tìm hiểu lý do tại sao anh ta sử dụng chúng ở mọi nơi . Tràn đầy dẫn đến những tình huống cực kỳ xấu xí, những tình huống mà tôi thấy khá khó khăn để xác định và giải quyết. Nếu anh ta lạm dụng BC Math, có thể chỉ vì anh ta bị mắc kẹt khủng khiếp một lần và cố gắng chơi nó an toàn nhất có thể. Mặc dù không có gì sai khi sử dụng BC Math, nhưng hình phạt hiệu suất không đáng kể có thể là một vấn đề nghiêm trọng trong một số tình huống. Nếu bạn nhận thấy bất kỳ vấn đề về hiệu suất, hãy đảm bảo rằng bạn lập hồ sơ cho ứng dụng của mình và chắc chắn rằng đó là BC Math liên quan.

Luôn nhớ rằng các tính toán của bạn phải hoạt động chính xác:

  • Trên mọi hệ thống bạn đang nhắm mục tiêu, bao gồm các máy phát triển riêng lẻ và (tất nhiên) máy sản xuất.
  • Bất kể có thể nâng cấp hoặc hạ cấp hệ thống / nền tảng.

Trong phát triển đa nền tảng, bạn phải luôn coi giới hạn thấp nhất là giới hạn cứng. Nếu bạn hoàn toàn chắc chắn rằng các tính toán của bạn sẽ không vượt quá giới hạn (bao gồm cả kết quả của chúng), thì không có điểm nào trong việc sử dụng BC Math.

Nhưng nếu những gì bạn mô tả là anh ấy thích echo bcadd("1", "2");hơn echo 1+2;, chúc may mắn!


Tôi đã tìm thấy một bài đăng blog cực kỳ thú vị và có liên quan trong danh sách dấu trang khổng lồ của tôi, Số nguyên trong PHP, chạy bằng kéo và tính di động , trên blog Hiệu suất MySQL của Percona. Nó đã cũ (2007) nhưng nó cung cấp một cái nhìn tổng quan tốt về các snafus khác nhau với tính di động nguyên trong PHP.


1
Lưu ý rằng việc sử dụng các chuỗi là không cần thiết (thực tế, tôi tưởng tượng việc xử lý nội bộ khá xấu xí và phức tạp) đối với số học chính xác tùy ý, đó chỉ là một cách dễ dàng để có được chữ cho chúng.

@delnan Chuỗi được sử dụng để truyền tham số trong các hàm Binary Calculator vì rõ ràng, nếu bạn có thể sử dụng số nguyên, bạn sẽ không cần các hàm ... by representing arbitrary precision numbers as stringsĐược lấy từ hướng dẫn, bạn có đọc như một gợi ý về những gì diễn ra trong nội bộ ? - tức là không phải người nói tiếng Anh bản xứ, làm thế nào tôi có thể cải thiện phần đó?
yannis

Vâng, tôi nghĩ có thể đọc là "BC Math sử dụng các chuỗi xen kẽ" (mặc dù tôi có một sự hiểu biết đầy đủ về số học chính xác của số liệu để nghi ngờ đó thực sự là trường hợp), vì đó gần như là những gì bạn nêu (bên dưới trích dẫn thứ ba) . Tôi cũng không phải là người bản ngữ, nhưng tôi tưởng tượng sẽ an toàn hơn khi nêu một tương tác với BC Math thông qua các chuỗi.

@delnan Cảm ơn, tôi hiểu ý của bạn. Trong tâm trí của tôi, cụm từ không đề xuất những gì diễn ra trong nội bộ, vì việc sử dụng thư viện thực sự là để giúp bạn không quan tâm đến những gì diễn ra trong nội bộ, nhưng tôi thấy nó khó hiểu và có thể gây hiểu lầm.
yannis

@delnan Cập nhật câu trả lời.
yannis

4

Có lời khuyên tốt nào liên quan đến điều này hoặc những điều cần ghi nhớ?

Sử dụng các hàm toán học BC trong PHP có những ưu điểm và nhược điểm.

Ưu điểm:

  • bạn có thể thực hiện các phép tính cơ bản trên các số với "số có kích thước và độ chính xác bất kỳ".

Nhược điểm:

  • phép tính không phải là nguồn gốc (các phép tính trên Integer hoặc Float là nguồn gốc PHP và thường là CPU gốc)
  • các số được quản lý dưới dạng chuỗi
  • mã không dễ đọc

Vì vậy, chúng ta có thể thấy rằng BC Math được dành riêng cho một cách sử dụng cụ thể và có thể làm xáo trộn các công thức và thậm chí các thuật toán, đồng thời làm chậm các phép tính lớn.

Vì vậy, nên hiểu các tính toán kinh doanh của bạn để tìm ra khi nào các chức năng đó thực sự cần thiết và chúng vô dụng ở đâu. Vì vậy, ở đây bạn phải tập trung vào tốc độ mã và khả năng đọc mã. Sau đó, thích hợp để chọn quy ước mã hóa của dự án về việc sử dụng BC Math.

Để làm như vậy, bạn phải hiểu sự khác biệt về kỹ thuật giữa các phép tính riêng của PHP và Hàm toán học BC. Đó là câu hỏi của bạn "Kích thước bất kỳ là bao nhiêu? Độ nổi mặc định trong PHP là bao nhiêu?"

Bao nhiêu là kích thước?

Chúng tôi không thể tìm thấy nhiều tài liệu về anh ấy. Có lẽ miễn là một chuỗi có thể có trong PHP.

Làm thế nào lớn là float nổi mặc định trong PHP?

"Kích thước của một float là phụ thuộc vào nền tảng, mặc dù tối đa ~ 1.8e308 với độ chính xác khoảng 14 chữ số thập phân là một giá trị phổ biến (định dạng IEEE 64 bit)."

Thêm chi tiết tại hướng dẫn PHP .

Lưu ý rằng PHP cũng cung cấp cho các Hàm GMP thực hiện các phép tính trên các số nguyên lớn.


1

Tôi thấy bcmath thân thiện hơn nhiều so với sử dụng so với GMP. Cho đến nay tôi thậm chí không thể tìm ra cách xử lý các phép tính dấu phẩy động với GMP trong PHP. Tất cả các công cụ dấu phẩy động dường như đã bị bỏ qua trong bản phát hành PHP. Vì vậy, tôi gắn bó với bcmath (bây giờ).

GMP trên PHP dường như hướng đến các tính toán lý thuyết số chứ không phải tính toán số như số thập phân của pi (hoặc e) và tương tự.


0

"Có lời khuyên tốt nào liên quan đến vấn đề này hay những điều cần ghi nhớ không?"

Không có thay thế thực sự cho:

  1. biết những hạn chế của nền tảng PHP của bạn và

  2. hiểu các yêu cầu tính toán của vấn đề của bạn.

Ngoài ra, một số hiểu biết về toán học tính toán luôn hữu ích.


0
"When must arbitrary precision arithmetic functions be used in PHP?"

Tôi chưa bao giờ nghe nói về một trang web phải sử dụng các hàm bcmath trong PHP cho những gì có thể được coi là thông lệ bình thường và hãy nhớ rằng hầu hết các trang web lớn nhất trên internet đều sử dụng số lượng đáng kể PHP và hơn 240 triệu "nhỏ hơn" "Các trang web được mã hóa bằng PHP.

bcmath thường được sử dụng cho các trường hợp cực đoan trong đó các số có khả năng trở nên rất lớn hoặc rất nhỏ, thay vì các trường hợp cần 'dài' thay vì int, hoặc khi kích thước cụ thể của int hoặc float là một mối quan tâm.

"How much is any size?"

bcmath chỉ bị giới hạn bởi bộ nhớ và trong thực tế đây không phải là giới hạn thực sự. Một thử nghiệm nhanh với bcmath cho thấy nó có thể xử lý các số lớn hơn 2 ^ 1000000 (tức là 301.030 chữ số, một triệu chỉ có bảy chữ số) và '0,1 - 2 ^ 1000000' dẫn đến tỷ lệ âm bằng nhau.

Theo như hiệu suất, bcmath nhanh nhưng có thể tiêu tốn rất nhiều bộ nhớ. Về cơ bản, nó tính toán các con số giống như cách chúng ta (như con người) sử dụng bút trong pad. Các số thực có thể được xử lý chỉ trong vài trăm bước, thường dẫn đến chỉ vài mili giây. Nhưng những bản sao chuỗi 'vài trăm' này sẽ cộng lại trong bộ nhớ. Lưu ý các con số ở trên (2 ^ 1000000) là lớn không thể tin nổi và mất máy tính xách tay khá cũ của tôi 2-3 giây để xử lý.

"Is it really necessary?"

Tóm lại, có, nhưng rất hiếm khi.

Ví dụ, băm SHA-1 thực sự là các số, không phải là chuỗi. Số cao nhất có thể sử dụng SHA-1 là 2 ^ 160, hoặc 1.461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976. Không có cách nào để làm việc với các số như vậy bằng cách sử dụng các kiểu dữ liệu nguyên gốc và làm việc với băm SHA-1 (dưới dạng số) là khá phổ biến trong các thuật toán phân tán.

Một lần nữa, điều này là hiếm, nhưng khi nó thực sự không có gì thay thế, bất kể hệ thống hoặc khung ưu tiên của bạn.

"Advise"

Không sử dụng bcmath trừ khi bạn biết đó là những gì bạn cần hoặc chỉ thích chơi với những con số. Nó sẽ không phá vỡ bất cứ điều gì và không nên gây ra các vấn đề hiệu năng đáng chú ý, nhưng hầu hết các vấn đề có thể được giải quyết bằng cách sử dụng các kiểu dữ liệu tiêu chuẩn của PHP.


SHA-1 hoạt động trên một số nguyên 32 bit bên trong. Bên ngoài nó hoạt động trên chuỗi byte. Vì vậy, nó gần với chuỗi hơn là số lớn. Nó hiếm khi hữu ích để coi nó như một số nguyên 160 bit. (Có những khu vực khác của crypto, như RSA mà sử dụng số nguyên lớn trong nội bộ, nhưng bạn không nên thực hiện những người trên một mục đích chung thư viện số nguyên lớn vì đó sẽ mở ra tấn công kênh bên)
CodesInChaos

Hmm, tôi đoán MIT đã sai khi họ tạo ra Hợp âm . Tôi có thể nghe thấy đám mây vỡ vụn khi tôi gõ: P
JSON

BTW, quyền của bạn khi nói đến nội bộ của SHA1.
JSON

Hợp âm có thể hiểu băm SHA-1 là một số lượng lớn. Không phải vì SHA-1 có liên quan đến các số nguyên lớn, mà bởi vì giao thức được xây dựng trên nó có thể thấy thuận tiện khi làm như vậy. Các DHT sử dụng thước đo khoảng cách giữa các giá trị băm, chúng có thể được biểu thị bằng các số nguyên lớn.
CodeInChaos

Trước hết, số nguyên lớn là một loại giả. Chúng không tồn tại nguyên bản bất kỳ hệ thống. Chúng là các chuỗi char bên trong, mặc dù một số triển khai cho phép các số nguyên lớn được thể hiện dưới dạng "số" thực tế trong mã (1234323456654322345 thay vì "1234323456654322345" như Java). Việc triển khai như vậy vẫn tạo ra chuỗi char khi mã số được biên dịch.
JSON
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.