PHP強化之02 - 數(shù)字 Math(新)

----- 最后更新【2022-01-06】-----

PHP強化系列--目錄

本文目錄結(jié)構(gòu)預(yù)覽:

  • 一捉超、定義
    1胧卤、整型值 Integer
    2、浮點型 Float
    3拼岳、數(shù)字字符串
  • 二枝誊、關(guān)于最大值范圍
  • 三、類型轉(zhuǎn)換
    1惜纸、轉(zhuǎn)換為整形
    2叶撒、轉(zhuǎn)換為浮點形
    3、轉(zhuǎn)換進制
    4耐版、ASCII 字符轉(zhuǎn)換
  • 四祠够、常用函數(shù)
    1、數(shù)字類型的判斷
    2椭更、小數(shù)與整數(shù)的舍取
    3哪审、數(shù)字的自動生成
    4、常用數(shù)學(xué)方法
    5虑瀑、格式化一個數(shù)字
  • 五湿滓、參考

一、定義

在PHP中舌狗,數(shù)字主要被分為三種類型:整型(Integer)叽奥、浮點型(Float)、數(shù)字字符串痛侍。

1朝氓、整型值 Integer

整型值 int 可以使用十進制,十六進制主届,八進制或二進制表示赵哲,前面可以加上可選的符號(- 或者 +)。

八進制表示:數(shù)字前必須加上0(零)君丁,PHP 8.1.0 起枫夺,八進制表示也可以在前面加上0o或者0O
十六進制表示:數(shù)字前必須加上0x或者0X绘闷。
二進制表示:數(shù)字前必須加上0b或者0B橡庞。

$a = 1234; // 十進制數(shù)
$a = 0123; // 八進制數(shù) (等于十進制 83)
$a = 0o123; // 八進制數(shù) (PHP 8.1.0 起)
$a = 0x1A; // 十六進制數(shù) (等于十進制 26)
$a = 0b11111111; // 二進制數(shù)字 (等于十進制 255)
$a = 1_234_567; // 整型數(shù)值 (PHP 7.4.0 以后)

從 PHP 7.4.0 開始,數(shù)字類型都允許使用下劃線(_)語法印蔗,這是為了提高了代碼的可讀性和質(zhì)量扒最。這些下劃線在PHP執(zhí)行代碼的時候,會自動被過濾掉华嘹。如$a = 1_234_567;吧趣,實際的值依然是 Integer 型123456

用正則表達式來定義耙厚,組成 Integer 的語法結(jié)構(gòu)如下(PHP 7.4+):

decimal(十進制)       : [1-9][0-9]*(_[0-9]+)* | 0

hexadecimal(十六進制) : 0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*

octal(八進制)         : 0[oO]?[0-7]+(_[0-7]+)*

binary(二進制)        : 0[bB][01]+(_[01]+)*

integer(整型)         : decimal | hexadecimal | octal | binary

注:如果是PHP 7.3 及以前版本强挫,則上面的表達式只需要把(...)*這部分內(nèi)容去掉就行,如十進制為[1-9][0-9]* | 0颜曾。

2纠拔、浮點型 Float

浮點型(也叫浮點數(shù) Float、雙精度數(shù) Double 或 實數(shù) Real)泛豪,如下都是浮點類型:

$a = 1.234; 
$b = 1.2e3;  // 1200
$c = 7E-15;  // 7.0 乘以 10 的 負15次方
$d = 1_234.567; // 從 PHP 7.4.0 開始支持

用正則表達式來定義稠诲,組成 Float 的語法結(jié)構(gòu)如下(PHP 7.4+):

LNUM(整數(shù))           : [0-9]+(_[0-9]+)*
DNUM(小數(shù))           : ([0-9]*(_[0-9]+)*[\.]{LNUM}) | ({LNUM}[\.][0-9]*(_[0-9]+)*)
EXPONENT_DNUM(指數(shù))  : (({LNUM} | {DNUM}) [eE][+-]? {LNUM})

Tip:上面的{LNUM}相當(dāng)一個占位符,把它替換成相應(yīng)的值就行诡曙,PHP 7.3 及以前版本去掉(_[0-9]+)*這部分臀叙。

注意:
永遠不要相信浮點數(shù)結(jié)果精確到了最后一位,也永遠不要比較兩個浮點數(shù)是否相等价卤。例如劝萤,floor((0.1+0.7)*10) 通常會返回 7 而不是預(yù)期中的 8,因為該結(jié)果內(nèi)部的表示其實是類似 7.9999999999999991118...慎璧。

$a = 0.1;
$b = 0.7
if($a +$b == 0.8) {
  //判斷結(jié)果為false,不會進來這里床嫌。
}

超出表示范圍的浮點型(9223372036854775807為64位系統(tǒng)能表示的最大整型值):

php > $a = pow(2, 62)+(pow(2, 62)-1);
php > var_dump($a);
int(9223372036854775807)
php > $b = $a+1;
php > $c = $a+21;
php > var_dump($b==$c);
bool(true)
php > var_dump($b,$c);
float(9.2233720368548E+18)
float(9.2233720368548E+18)

3跨释、數(shù)字字符串

如果一個 PHP string 可以被解釋為 int 或 float 類型,則它被視為數(shù)字字符串厌处。PHP 8.0.0+可如下表示:

WHITESPACES      \s*
LNUM             [0-9]+
DNUM             ([0-9]*)[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM    (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
INT_NUM_STRING   {WHITESPACES} [+-]? {LNUM} {WHITESPACES}
FLOAT_NUM_STRING {WHITESPACES} [+-]? ({DNUM} | {EXPONENT_DNUM}) {WHITESPACES}
NUM_STRING       ({INT_NUM_STRING} | {FLOAT_NUM_STRING})

PHP 也有前導(dǎo)數(shù)字字符串的概念(這只是一個字符串鳖谈,其開頭類似于數(shù)字字符串,后跟任何字符)阔涉。

當(dāng)一個 string 需要被當(dāng)作一個數(shù)字計算時(例如:算術(shù)運算缆娃, int 類型聲明等),則采取以下步驟來確定結(jié)果:
(1) 如果 string 是數(shù)字瑰排,當(dāng) string 是整數(shù)字符串并且符合 int 類型的范圍限制(即是 PHP_INT_MAX 定義的值)贯要,則解析為 int ,否則解析為 float 椭住。
(2) 如果上下文允許前導(dǎo)數(shù)字和一個 string崇渗,如果 string 的前導(dǎo)部分是整數(shù)數(shù)字字符串且符合 int 類型限制(由 PHP_INT_MAX 定義),則解析為 int 函荣,否則解析為 float 显押。 此外,還會導(dǎo)致 E_WARNING 級別的錯誤傻挂。
(3) 如果 string 不是數(shù)字乘碑,則會拋出一個 TypeError 的異常。

二金拒、關(guān)于最大值范圍

目錄大部分系統(tǒng)都是64位兽肤,所以這里也以64位為基礎(chǔ)展開解說。

關(guān)于取值范圍:
整型數(shù) int 的字長和平臺有關(guān)绪抛,盡管通常最大值是大約二十億(32 位有符號)资铡。64 位平臺下的最大值通常是大約 9E18。 PHP 不支持無符號的 int幢码。int 值的字長可以用常量 PHP_INT_SIZE來表示笤休, 最大值可以用常量 PHP_INT_MAX 來表示, 最小值可以用常量 PHP_INT_MIN 表示症副。

查看最大值與最小值:

php > var_dump(PHP_INT_MIN);
int(-9223372036854775808)
php > var_dump(PHP_INT_MAX);
int(9223372036854775807)

二進制表示:

查看 64 位系統(tǒng)平臺中店雅,PHP的 Int 類型最大值:

php > $a = 9223372036854775807;
php > var_dump($a);
int(9223372036854775807)
php > $a += 1 ;
php > var_dump($a);
float(9.223372036854776E+18)

9223372036854775807 為 2 的 63 次方 再減 1 的值,因為還有一位要用來表示符號贞铣,所以不是 64 次方闹啦。
當(dāng) Integer 類型的數(shù)值超過上面的最大值后,PHP 會將它自動轉(zhuǎn)換為浮點類型辕坝。

注意:如果一個浮點值的類型不在 int 型能表示的范圍窍奋,將它強制轉(zhuǎn)換為 Int 型則會出現(xiàn)問題。

php > var_dump($a);
int(9223372036854775807)
php > $a += 1 ;
php > var_dump($a);
float(9.223372036854776E+18)
php > $a = (int) $a;
php > var_dump($a);
int(-9223372036854775808)

三、類型轉(zhuǎn)換

1琳袄、轉(zhuǎn)換為整形

方法一:使用(int)(integer)轉(zhuǎn)換成整形
方法二:使用intval($var)把 $var 轉(zhuǎn)換成整形
方法三:使用settype($var, "integer")江场,第二個參數(shù)也可以設(shè)成int

$num = 3.14;   
$num1 = (int) $num; 
var_dump($num1); //輸出int(3)   

2挚歧、轉(zhuǎn)換為浮點形

方法一:使用(float)扛稽、(double)(real)轉(zhuǎn)換成浮點形
方法二:使用floatval($var)把 $var 轉(zhuǎn)換成浮點形
方法三:使用settype($var, "float")吁峻,對于舊版本中使用的double現(xiàn)已停用。

$num = '3.14ab';   
$num1 = (float) $num;  
var_dump($num1); //輸出float(3.14)     
var_dump(floatval($num)); //輸出float(3.14)     

3、轉(zhuǎn)換進制

函數(shù) 說明
base_convert 在任意進制之間轉(zhuǎn)換數(shù)字
bindec 二進制轉(zhuǎn)換為十進制
decbin 十進制轉(zhuǎn)換為二進制
octdec 八進制轉(zhuǎn)換為十進制
decoct 十進制轉(zhuǎn)換為八進制
hexdec 十六進制轉(zhuǎn)換為十進制
dechex 十進制轉(zhuǎn)換為十六進制

例1: base_convert — 在任意進制之間轉(zhuǎn)換數(shù)字
string base_convert ( string $number , int $frombase , int $tobase )
返回一字符串叛薯,包含 number 以 tobase 進制的表示谱俭。number 本身的進制由 frombase 指定。frombase 和 tobase 都只能在 2 和 36 之間(包括 2 和 36)啄骇。高于十進制的數(shù)字用字母 a-z 表示痴鳄,例如 a 表示 10,b 表示 11 以及 z 表示 35缸夹。

php > $hexadecimal = 'A37334';
php > echo base_convert($hexadecimal, 16, 2);  // 16進制 轉(zhuǎn)為 2進制
101000110111001100110100

例2:八進制'141'對應(yīng)的十進制為'97'痪寻。

php > echo octdec('141');
97

4、ASCII 字符轉(zhuǎn)換

函數(shù) 說明
hex2bin 把十六進制值轉(zhuǎn)換為 ASCII 字符
bin2hex 把 ASCII 字符的字符串轉(zhuǎn)換為十六進制值

例:十六進制值 "68692c4e6f536565" 轉(zhuǎn)換為對應(yīng)的 ASCII 字符

php > echo hex2bin('68692c4e6f536565');
hi,NoSee

四虽惭、常用函數(shù)

1橡类、數(shù)字類型的判斷

函數(shù) 說明
is_numeric 檢測變量是否為數(shù)字或數(shù)字字符串
is_int 檢測變量是否是整數(shù)。別名:is_integer芽唇、is_long
is_float 檢測變量是否是浮點型顾画。:別名:is_double、is_real

例1:—檢測變量是否為數(shù)字或數(shù)字字符串
bool is_numeric ( mixed $var)
檢測變量是否為數(shù)字或數(shù)字字符串匆笤,如果var是數(shù)字或數(shù)字字符串則返回TRUE研侣,否則返回FALSE。
注意還要考慮科學(xué)記數(shù)法和其它進制數(shù)炮捧。

php > var_dump(is_numeric('22e33'));
bool(true)
php > var_dump(is_numeric(0xA3));
bool(true)
php > var_dump(is_numeric('0xA3'));
bool(false)
php > var_dump(is_numeric('5,321'));
bool(false)
php > var_dump(is_numeric(0b0101));
bool(true)
php > var_dump(is_numeric('0b0101'));
bool(false)

例2:用正則表達式判斷是否是整數(shù)

preg_match("/^[1-9][0-9]*$|^0$/", $val)  

注意:這里的正則表達式不用加入下劃線的表達式(_[0-9]+)*庶诡,下劃線只是在編寫代碼時候給程序員自己看的,php內(nèi)部保存的還是純數(shù)字

例3:用 is_int 檢測變量是否是整數(shù)
bool is_int ( mixed $var )

php > var_dump(is_int('5'));
bool(false)
php > var_dump(is_int(5));
bool(true)
php > var_dump(is_int(5.0));
bool(false)
php > var_dump(is_int(0));
bool(true)

2咆课、小數(shù)與整數(shù)的舍取

函數(shù) 說明
round 對浮點數(shù)進行四舍五入
ceil 進一法取整
floor 舍去法取整
abs 絕對值

例1:round() 對浮點數(shù)進行四舍五入
float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )
返回將val根據(jù)指定精度precision(十進制小數(shù)點后數(shù)字的數(shù)目)進行四舍五入的結(jié)果末誓。precision也可以是負數(shù)或零(默認值)。

echo round(3.4);         // 3
echo round(3.5);         // 4
echo round(1.95583, 2);  // 1.96
echo round(1241757, -3); // 1242000

如傳入第三個參數(shù)mode值為以下之一(剛好需要舍取的下一位數(shù)剛好為5的情況): PHP_ROUND_HALF_UP(向上舍瓤觥)基显、PHP_ROUND_HALF_DOWN(向下舍取)善炫、PHP_ROUND_HALF_EVEN(取最近的偶數(shù))或PHP_ROUND_HALF_ODD(取最近的奇數(shù))

3撩幽、數(shù)字的自動生成

函數(shù) 說明
range 根據(jù)范圍創(chuàng)建數(shù)組,包含指定的元素
rand 產(chǎn)生一個隨機整數(shù)
mt_rand 生成更好的隨機數(shù)
getrandmax 顯示隨機數(shù)最大的可能值
mt_getrandmax 顯示隨機數(shù)的最大可能值

如果沒有提供可選參數(shù) min 和 max,rand() 返回 0 到 getrandmax() 之間的偽隨機整數(shù)窜醉。
如果沒有提供可選參數(shù) min 和 max宪萄,mt_rand() 返回 0 到 mt_getrandmax() 之間的偽隨機數(shù)。

很多老的 libc 的隨機數(shù)發(fā)生器具有一些不確定和未知的特性而且很慢榨惰。PHP 的rand()函數(shù)默認使用 libc 隨機數(shù)發(fā)生器拜英。mt_rand() 函數(shù)是非正式用來替換它的。該函數(shù)用了 ? Mersenne Twister中已知的特性作為隨機數(shù)發(fā)生器琅催,它可以產(chǎn)生隨機數(shù)值的平均速度比 libc 提供的 rand() 快四倍居凶。

例:建立一個包含指定范圍單元的數(shù)組

range(3,7,2);
//返回結(jié)果如下:
array(3) {
  [0]=>
  int(3)
  [1]=>
  int(5)
  [2]=>
  int(7)
}

4、常用數(shù)學(xué)方法

函數(shù) 說明
log 自然對數(shù)
log10 以 10 為底的對數(shù)
exp 計算 e 的指數(shù)
pow 指數(shù)表達式
sqrt 平方根
pi 得到圓周率值

例:

php > var_dump(log(256,2));  # 2為底數(shù)
float(8)
php > var_dump(log(256));  # e為底數(shù)
float(5.5451774444796)
php > echo pi();   # 圓周率
3.1415926535898
php > var_dump(pow(2, 8)); # 2的8次方
int(256)
php > echo sqrt(9);  # 平方根計算
3
php > echo M_PI; 
3.1415926535898  # 圓周率

注:PHP 的預(yù)定義數(shù)學(xué)常量
M_PI = 3.14159265358979323846藤抡,圓周率 pi
M_E = 2.7182818284590452354侠碧,自然對數(shù) e
官方查看:https://www.php.net/manual/zh/math.constants.php#math.constants

5、格式化一個數(shù)字

函數(shù) 說明
number_format 以千位分隔符方式格式化一個數(shù)字
money_format 將數(shù)字格式化成貨幣字符串

例1:number_format 使用方法
string number_format ( float $number [, int $decimals = 0 ] )
string number_format ( float $number , int $decimals = 0 , string $dec_point = "." , string $thousands_sep = "," )
本函數(shù)可以接受1個缠黍、2個或者4個參數(shù)(注意:不能是3個):

如果只提供第一個參數(shù)弄兜,number的小數(shù)部分會被去掉 并且每個千位分隔符都是英文小寫逗號","
如果提供兩個參數(shù),number將保留小數(shù)點后的位數(shù)到你設(shè)定的值瓷式,其余同樓上
如果提供了四個參數(shù)替饿,number 將保留decimals個長度的小數(shù)部分, 小數(shù)點被替換為dec_point,千位分隔符替換為thousands_sep

php > echo number_format(1234.56789);
1,235
php > echo number_format(1234.56789,2);
1,234.57
php > echo number_format(1234.56789,2,'.',',');
1,234.57
php > echo number_format(1234.56789,6,'.',',');
1,234.567890

例2:
場景:默認地贸典,number_format函數(shù)會把這個數(shù)舍入到最接近的整數(shù)视卢。如果想你保留整個數(shù),但又無法提前知道小數(shù)點后有多少位瓤漏,這時你該怎么辦腾夯?可以使用以下解決方法:

$number = 31415.93421;  //你的數(shù)
list($int,$dec) = explode('.', $number);
$formatted = number_format($number,strlen($dec)); //$formatted為:31,415.93421

五蔬充、參考

1蝶俱、官方文檔:
Integer 整型 - http://php.net/manual/zh/language.types.integer.php
Float 浮點型 - http://php.net/manual/zh/language.types.float.php
數(shù)字字符串 - https://www.php.net/manual/zh/language.types.numeric-strings.php
Math 函數(shù) - http://php.net/manual/zh/ref.math.php

2、相關(guān)書籍:
《PHP經(jīng)典實例》 David Sklar & Adam Trachtenberg

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饥漫,一起剝皮案震驚了整個濱河市榨呆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庸队,老刑警劉巖积蜻,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異彻消,居然都是意外死亡竿拆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門宾尚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丙笋,“玉大人谢澈,你說我怎么就攤上這事∮澹” “怎么了锥忿?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怠肋。 經(jīng)常有香客問我敬鬓,道長,這世上最難降的妖魔是什么笙各? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任钉答,我火速辦了婚禮,結(jié)果婚禮上酪惭,老公的妹妹穿的比我還像新娘希痴。我一直安慰自己,他們只是感情好春感,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虏缸,像睡著了一般鲫懒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刽辙,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天窥岩,我揣著相機與錄音宰缤,去河邊找鬼颂翼。 笑死,一個胖子當(dāng)著我的面吹牛慨灭,可吹牛的內(nèi)容都是我干的朦乏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼氧骤,長吁一口氣:“原來是場噩夢啊……” “哼呻疹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起筹陵,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤刽锤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后朦佩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體并思,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年语稠,在試婚紗的時候發(fā)現(xiàn)自己被綠了宋彼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宙暇,靈堂內(nèi)的尸體忽然破棺而出输枯,到底是詐尸還是另有隱情,我是刑警寧澤占贫,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布桃熄,位于F島的核電站,受9級特大地震影響型奥,放射性物質(zhì)發(fā)生泄漏瞳收。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一厢汹、第九天 我趴在偏房一處隱蔽的房頂上張望螟深。 院中可真熱鬧,春花似錦烫葬、人聲如沸界弧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垢箕。三九已至,卻和暖如春兑巾,著一層夾襖步出監(jiān)牢的瞬間条获,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工蒋歌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帅掘,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓堂油,卻偏偏與公主長得像修档,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子称诗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容