PHP强化之02 - 数字 Math(新)

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

PHP强化系列--目录

本文目录结构预览:

  • 一、定义
    1、整型值 Integer
    2、浮点型 Float
    3、数字字符串
  • 二、关于最大值范围
  • 三、类型转换
    1、转换为整形
    2、转换为浮点形
    3、转换进制
    4、ASCII 字符转换
  • 四、常用函数
    1、数字类型的判断
    2、小数与整数的舍取
    3、数字的自动生成
    4、常用数学方法
    5、格式化一个数字
  • 五、参考

一、定义

在PHP中,数字主要被分为三种类型:整型(Integer)、浮点型(Float)、数字字符串。

1、整型值 Integer

整型值 int 可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号(- 或者 +)。

八进制表示:数字前必须加上0(零),PHP 8.1.0 起,八进制表示也可以在前面加上0o或者0O
十六进制表示:数字前必须加上0x或者0X
二进制表示:数字前必须加上0b或者0B

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

从 PHP 7.4.0 开始,数字类型都允许使用下划线(_)语法,这是为了提高了代码的可读性和质量。这些下划线在PHP执行代码的时候,会自动被过滤掉。如$a = 1_234_567;,实际的值依然是 Integer 型123456

用正则表达式来定义,组成 Integer 的语法结构如下(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 及以前版本,则上面的表达式只需要把(...)*这部分内容去掉就行,如十进制为[1-9][0-9]* | 0

2、浮点型 Float

浮点型(也叫浮点数 Float、双精度数 Double 或 实数 Real),如下都是浮点类型:

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

用正则表达式来定义,组成 Float 的语法结构如下(PHP 7.4+):

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

Tip:上面的{LNUM}相当一个占位符,把它替换成相应的值就行,PHP 7.3 及以前版本去掉(_[0-9]+)*这部分。

注意:
永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999999991118...。

$a = 0.1;
$b = 0.7
if($a +$b == 0.8) {
  //判断结果为false,不会进来这里。
}

超出表示范围的浮点型(9223372036854775807为64位系统能表示的最大整型值):

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、数字字符串

如果一个 PHP string 可以被解释为 int 或 float 类型,则它被视为数字字符串。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 也有前导数字字符串的概念(这只是一个字符串,其开头类似于数字字符串,后跟任何字符)。

当一个 string 需要被当作一个数字计算时(例如:算术运算, int 类型声明等),则采取以下步骤来确定结果:
(1) 如果 string 是数字,当 string 是整数字符串并且符合 int 类型的范围限制(即是 PHP_INT_MAX 定义的值),则解析为 int ,否则解析为 float 。
(2) 如果上下文允许前导数字和一个 string,如果 string 的前导部分是整数数字字符串且符合 int 类型限制(由 PHP_INT_MAX 定义),则解析为 int ,否则解析为 float 。 此外,还会导致 E_WARNING 级别的错误。
(3) 如果 string 不是数字,则会抛出一个 TypeError 的异常。

二、关于最大值范围

目录大部分系统都是64位,所以这里也以64位为基础展开解说。

关于取值范围:
整型数 int 的字长和平台有关,尽管通常最大值是大约二十亿(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 位系统平台中,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 次方。
当 Integer 类型的数值超过上面的最大值后,PHP 会将它自动转换为浮点类型。

注意:如果一个浮点值的类型不在 int 型能表示的范围,将它强制转换为 Int 型则会出现问题。

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)

三、类型转换

1、转换为整形

方法一:使用(int)(integer)转换成整形
方法二:使用intval($var)把 $var 转换成整形
方法三:使用settype($var, "integer"),第二个参数也可以设成int

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

2、转换为浮点形

方法一:使用(float)(double)(real)转换成浮点形
方法二:使用floatval($var)把 $var 转换成浮点形
方法三:使用settype($var, "float"),对于旧版本中使用的double现已停用。

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

3、转换进制

函数 说明
base_convert 在任意进制之间转换数字
bindec 二进制转换为十进制
decbin 十进制转换为二进制
octdec 八进制转换为十进制
decoct 十进制转换为八进制
hexdec 十六进制转换为十进制
dechex 十进制转换为十六进制

例1: base_convert — 在任意进制之间转换数字
string base_convert ( string $number , int $frombase , int $tobase )
返回一字符串,包含 number 以 tobase 进制的表示。number 本身的进制由 frombase 指定。frombase 和 tobase 都只能在 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。

php > $hexadecimal = 'A37334';
php > echo base_convert($hexadecimal, 16, 2);  // 16进制 转为 2进制
101000110111001100110100

例2:八进制'141'对应的十进制为'97'。

php > echo octdec('141');
97

4、ASCII 字符转换

函数 说明
hex2bin 把十六进制值转换为 ASCII 字符
bin2hex 把 ASCII 字符的字符串转换为十六进制值

例:十六进制值 "68692c4e6f536565" 转换为对应的 ASCII 字符

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

四、常用函数

1、数字类型的判断

函数 说明
is_numeric 检测变量是否为数字或数字字符串
is_int 检测变量是否是整数。别名:is_integer、is_long
is_float 检测变量是否是浮点型。:别名:is_double、is_real

例1:—检测变量是否为数字或数字字符串
bool is_numeric ( mixed $var)
检测变量是否为数字或数字字符串,如果var是数字或数字字符串则返回TRUE,否则返回FALSE。
注意还要考虑科学记数法和其它进制数。

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:用正则表达式判断是否是整数

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

注意:这里的正则表达式不用加入下划线的表达式(_[0-9]+)*,下划线只是在编写代码时候给程序员自己看的,php内部保存的还是纯数字

例3:用 is_int 检测变量是否是整数
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、小数与整数的舍取

函数 说明
round 对浮点数进行四舍五入
ceil 进一法取整
floor 舍去法取整
abs 绝对值

例1:round() 对浮点数进行四舍五入
float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )
返回将val根据指定精度precision(十进制小数点后数字的数目)进行四舍五入的结果。precision也可以是负数或零(默认值)。

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

如传入第三个参数mode值为以下之一(刚好需要舍取的下一位数刚好为5的情况): PHP_ROUND_HALF_UP(向上舍取)、PHP_ROUND_HALF_DOWN(向下舍取)、PHP_ROUND_HALF_EVEN(取最近的偶数)或PHP_ROUND_HALF_ODD(取最近的奇数)

3、数字的自动生成

函数 说明
range 根据范围创建数组,包含指定的元素
rand 产生一个随机整数
mt_rand 生成更好的随机数
getrandmax 显示随机数最大的可能值
mt_getrandmax 显示随机数的最大可能值

如果没有提供可选参数 min 和 max,rand() 返回 0 到 getrandmax() 之间的伪随机整数。
如果没有提供可选参数 min 和 max,mt_rand() 返回 0 到 mt_getrandmax() 之间的伪随机数。

很多老的 libc 的随机数发生器具有一些不确定和未知的特性而且很慢。PHP 的rand()函数默认使用 libc 随机数发生器。mt_rand() 函数是非正式用来替换它的。该函数用了 » Mersenne Twister中已知的特性作为随机数发生器,它可以产生随机数值的平均速度比 libc 提供的 rand() 快四倍。

例:建立一个包含指定范围单元的数组

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

4、常用数学方法

函数 说明
log 自然对数
log10 以 10 为底的对数
exp 计算 e 的指数
pow 指数表达式
sqrt 平方根
pi 得到圆周率值

例:

php > var_dump(log(256,2));  # 2为底数
float(8)
php > var_dump(log(256));  # e为底数
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 的预定义数学常量
M_PI = 3.14159265358979323846,圆周率 pi
M_E = 2.7182818284590452354,自然对数 e
官方查看:https://www.php.net/manual/zh/math.constants.php#math.constants

5、格式化一个数字

函数 说明
number_format 以千位分隔符方式格式化一个数字
money_format 将数字格式化成货币字符串

例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 = "," )
本函数可以接受1个、2个或者4个参数(注意:不能是3个):

如果只提供第一个参数,number的小数部分会被去掉 并且每个千位分隔符都是英文小写逗号","
如果提供两个参数,number将保留小数点后的位数到你设定的值,其余同楼上
如果提供了四个参数,number 将保留decimals个长度的小数部分, 小数点被替换为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函数会把这个数舍入到最接近的整数。如果想你保留整个数,但又无法提前知道小数点后有多少位,这时你该怎么办?可以使用以下解决方法:

$number = 31415.93421;  //你的数
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
数字字符串 - https://www.php.net/manual/zh/language.types.numeric-strings.php
Math 函数 - http://php.net/manual/zh/ref.math.php

2、相关书籍:
《PHP经典实例》 David Sklar & Adam Trachtenberg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容