對于各類開發語言來說,整數都有一個最大的位數,如果超過位數就無法顯示或者操作了,其實,這也是一種精度越界之后產生的精度丟失問題,在我們的 PHP 代碼中,最大的整數非常大,我們可以通過 PHP_INT_MAX 來查看,不過,當整數超過一定的位數之后,就會使用科學計數法來顯示了,這個可不是我們想要的結果,別著急,GMP 擴展就是專門用來應對這種情況的,
GMP 擴展是隨 PHP 原始碼包一起發布的,在安裝擴展之前需要系統環境中先安裝 gmp-devel ,在 CentOS 中直接 yun install gmp-devel 就可以了,
超大數字的精度丟失問題
我們先來看看直接列印輸出超大的數字會發生什么,
echo PHP_INT_MAX; // 92233720368547758071.2312312312312E+26
$a = 123123123123123123123123123;
echo $a, PHP_EOL; // 1.2312312312312E+26
echo $a + 1, PHP_EOL; // 1.2312312312312E+26
可以看到,顯示的結果都是科學計數法的形式了,而且對于簡單的運算操作來說,也基本看不到有什么區別了,就像我們最后給 $a + 1 的情況,它和原始的資料展示 出來的結果是一樣的,
$b = gmp_init("123123123123123123123123123");
echo $b, PHP_EOL; // 123123123123123123123123123
echo gmp_add($b, 1), PHP_EOL; // 123123123123123123123123124
當我們使用 GMP 擴展后,就可以使用 gmp_init() 來實體化這樣的超大數字,列印的結果還是標準的數字格式,不過,這里需要注意的是,這個擴展其實是將我們要操作的這種超大的數字轉換成了字串來表示,
gmp_add() 是 GMP 的加法操作函式,非常簡單,就是兩個引數進行相加,然后回傳的依然是一個 GMP 物件,
var_dump($b);
// object(GMP)#1 (1) {
// ["num"]=>
// string(27) "123123123123123123123123123"
// }
echo $b + 1, PHP_EOL; // 123123123123123123123123124
通過列印 gmp_init() 回傳的 $b 物件就可以看出來,它里面的內容其實是一個字串了,同時,這個物件還重寫了 __toString() 方法,所以我們可以直接 echo 它,另外,GMP 物件還多載了運算運算子,所以直接針對 GMP 物件進行日常的運算子運算也是沒有問題的,
簡單運算操作
除了多載的運算子之外,GMP 擴展也提供了一系列的運算操作函式,就像我們上面已經見過了 gmp_add() 一樣,
echo gmp_sub($b, 1), PHP_EOL; // 123123123123123123123123122
echo gmp_mul($b, 2), PHP_EOL; // 246246246246246246246246246
echo gmp_div("123123123123123123123123123", 3), PHP_EOL; // 41041041041041041041041041
echo gmp_mod($b, 5), PHP_EOL; // 3
這四個分別就是 減 、乘 、除 、余 的計算,非常地簡單,這里也就不多說了,在這里需要注意的一點是,它們接收的引數可以是 int 型別,也可以是 字串 型別,就和 gmp_init() 接收的引數一樣,
echo gmp_abs("-123123123123123123123123123"), PHP_EOL; // 123123123123123123123123123
echo gmp_pow($b, 3), PHP_EOL; // 1866460784838622135378351047886265184644645186267890058355382138624840786461867
echo gmp_sqrt($b), PHP_EOL; // 11096085937082
這三個函式分別是取絕對值、乘方、二次方根的計算函式,和普通的 Math 計算函式都是類似的,
位操作
GMP 擴展還可以方便地對資料進行位操作以及二進制操作,比如位操作中的 與 、或 、異或,
echo gmp_and($b, "2222222222"), PHP_EOL; // 2151965570
echo gmp_or($b, "2222222222"), PHP_EOL; // 123123123123123123193379775
echo gmp_xor($b, "3333333333"), PHP_EOL; // 123123123123123120012088038
還可以將一個數字轉換成二進制格式匯出,
echo gmp_export($b), PHP_EOL; // e?U??(c?O?
當然,也有對應的從二進制匯入的函式,這里我們就不做演示了,大家可以自己在檔案中查找相應的函式測驗了解,
$pop1 = gmp_init("10000101", 2); // 3
echo gmp_popcount($pop1), PHP_EOL;
$pop2 = gmp_init("11111110", 2); // 7
echo gmp_popcount($pop2), PHP_EOL;
gmp_popcount() 函式用于獲取二進制表示的字符中的 1 的數量,比如這段測驗代碼中回傳的結果,
$s1 = gmp_init("10111", 2);
echo gmp_scan0($s1, 0), PHP_EOL; // 3
$s2 = gmp_init("101110000", 2);
echo gmp_scan0($s2, 0), PHP_EOL; // 0
$s1 = gmp_init("10111", 2);
echo gmp_scan1($s1, 0), PHP_EOL; // 0
$s2 = gmp_init("101110000", 2);
echo gmp_scan1($s2, 0), PHP_EOL; // 4
gmp_scan0() 和 gmp_scan1() 函式則是分別查找第一個出現的 0 或 1 的位置,它的第二個引數是指明從哪個位置開始查找,另外,它們查找的方向都是從右向左開始查找,并且是從下標 0 的位置開始的哦,
其它運算操作
生成亂數
echo gmp_random_range("10000000000000", "99999999999999999"), PHP_EOL; // 83490559526159213
// 12500000000
echo gmp_random_bits(99999),PHP_EOL; // 289814632948807684404778811091812938699609………………
就和普通的生成亂數的函式一樣,只不過 GMP 擴展庫下面的這兩個函式能夠生成的數字范圍更大,而且回傳的也是 GMP 物件的格式,對于 gmp_random_bits() 來說,最大的范圍是 12500000000 ,我的機子如果使用這個隨機因子的話直接就會報超出記憶體了,而使用 99999 這個隨機因子生成的亂數字也已經非常大了,大家可以自己嘗試一下,
階乘
這個是普通的 Math 庫中所沒有的函式,直接幫我們計算階乘的結果,不用自己寫演算法了哦,
echo gmp_fact(5), PHP_EOL; // 120 5*4*3*2*1=120
echo gmp_fact(50), PHP_EOL; // 30414093201713378043612608166064768844377641568960512000000000000 50*49*48…………*2*1
素數
除了階乘之外,GMP 還提供了非常高大上的直接獲取和判斷素數的函式,一般來說,素數(質數)也是面試中非常常見的演算法題目,我們在面試的時候還是要掌握自己手寫的能力,但是手寫完之后能和面試官說一下 GMP 中已經有現成的函式了相信也會帶來一些加分,
echo gmp_nextprime(10), PHP_EOL; // 11
echo gmp_nextprime(1000), PHP_EOL; // 1009
echo gmp_prob_prime(6), PHP_EOL; // 0
echo gmp_prob_prime("1111111111111111111"), PHP_EOL; // 1
echo gmp_prob_prime(7), PHP_EOL; // 2
gmp_nextprime() 是獲取指定數字之后的下一個素數是多少,gmp_prob_prime() 則是判斷給寫的數字是否是素數,它有三種結果,0 表示不是素數,1 表示可能(疑似)素數,2 表示確定是素數,
資料的符號資訊
echo gmp_sign("500"), PHP_EOL; // 1
echo gmp_sign("-500"), PHP_EOL; // -1
echo gmp_sign("0"), PHP_EOL; // 0
最后這個 gmp_sign() 函式用來表示給定資料的符號資訊,也就是正負數,它也是三種結果,1 表示正數,-1 表示負數,0 表示 0 ,為什么會有一個特殊的 0 存在呢?因為 0 即不是正數也不是負數呀,它本身就是一個特殊的存在,
總結
關于 GMP 擴展還有很多方法并沒有一一列舉出來,在這里只是挑選了一些比較常用的內容給大家介紹一下,雖說是刷檔案,但也不能直接照搬檔案過來,所以更多的內容大家還是自行去檔案中查閱,我們學習的目的主要就是知道有這么個東西,不至于在真實的業務需求中踫到了相關的內容時抓瞎,
測驗代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/8.PHP中操作任意精度大小的GMP擴展學習.php
參考檔案:
https://www.php.net/manual/zh/book.gmp.php
===============
關注公眾號:【硬核專案經理】獲取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、專案管理學習資料
知乎、公眾號、抖音、頭條搜索【硬核專案經理】
B站ID:482780532
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/296007.html
標籤:PHP
上一篇:學習PHP中的任意精度擴展函式
下一篇:數學相關函式在PHP中的應用簡介
