PHP浮点数用法与问题总结
一,php浮点数用法
PHP浮点类型取整之ceil — 进一法取整
说明
float ceil ( float value )
返回不小于 value 的下一个整数,value 如果有小数部分则进一位。ceil() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。
例子 1. ceil() 例子
代码如下 | 复制代码 |
< ?php |
PHP浮点类型取整之floor — 舍去法取整
说明
float floor ( float value )
返回不大于 value 的下一个整数,将 value 的小数部分舍去取整。floor() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。
例子 1. floor() 例子
代码如下 | 复制代码 |
< ?php |
PHP浮点类型取整之round — 对浮点数进行四舍五入
说明
float round ( float val [, int precision] )
返回将 val 根据指定精度 precision(十进制小数点后数字的数目)进行四舍五入的结果。precision 也可以是负数或零(默认值)。
例子 1. round() 例子
代码如下 | 复制代码 |
|
PHP浮点类型取整之intval—对变数转成整数型态
例子intval()
代码如下 | 复制代码 |
< ?php echo intval(4.3); //4 echo intval(4.6); // 4 ?> |
二,浮点数转成字符串
PHP内置的echo, var_dump, json_encode, 字符串拼接等函数(指令)在显示浮点数时都有问题, 导致精度丢失.
代码如下 | 复制代码 |
<?php $a = 1315537636.338467; printf("%f", $a); echo "n"; echo $a . "n"; echo $a; echo "n"; ?> 结果 1315537636.338467 1315537636.3385 1315537636.3385 |
也就是说, 用PHP最顺手的方法将浮点数转成字符串或者显示是不行的, 必须使用printf/sprintf将浮点数转成字符串.
三,一个常见问题的解答
不过, 我当时遗漏了一点, 也就是对于如下的这个常见问题的回答:
代码如下 | 复制代码 |
<?php |
为啥输出57
为啥输出是57啊? PHP的bug么?
我相信有很多的同学有过这样的疑问, 因为光问我类似问题的人就很多, 更不用说bugs.php.net上经常有人问…
要搞明白这个原因, 首先我们要知道浮点数的表示(IEEE 754):
浮点数, 以64位的长度(双精度)为例, 会采用1位符号位(E), 11指数位(Q), 52位尾数(M)表示(一共64位).
符号位:最高位表示数据的正负,0表示正数,1表示负数。
指数位:表示数据以2为底的幂,指数采用偏移码表示
尾数:表示数据小数点后的有效数字.
这里的关键点就在于, 小数在二进制的表示, 关于小数如何用二进制表示, 大家可以百度一下, 我这里就不再赘述, 我们关键的要了解, 0.58 对于二进制表示来说, 是无限长的值(下面的数字省掉了隐含的1)..
0.58的二进制表示基本上(52位)是:
0010100011110101110000101000111101011100001010001111
0.57的二进制表示基本上(52位)是:
0010001111010111000010100011110101110000101000111101
而两者的二进制, 如果只是通过这52位计算的话,分别是:
0.58 -> 0.57999999999999996
0.57 -> 0.56999999999999995
至于0.58 * 100的具体浮点数乘法, 我们不考虑那么细, 有兴趣的可以看(Floating point), 我们就模糊的以心算来看… 0.58 * 100 = 57.999999999
那你intval一下, 自然就是57了….
可见, 这个问题的关键点就是: “你看似有穷的小数, 在计算机的二进制表示里却是无穷的”
四,float(浮点数)比较的问题
最近在开发一个合同管理系统的时候,涉及到两个浮点数比较,算是把我郁闷惨了。
在N久以前,就不晓得从哪里听来的一个“不要用等号去比较浮点数”的“真理”,自己平时也在用,好像没有出现啥问题,可这次问题总算是来了。
代码如下 | 复制代码 |
<?php |
结果是:
代码如下 | 复制代码 |
float(12300) |
后来才知道在PHP中,要比较两个浮点数的大小,可以用bccomp(参数1,参数2,小数位)来比较。
代码如下 | 复制代码 |
<?php 结果: float(12300) |
bccomp函数具体用法参与PHP手册
本文章晋级人各位同学介绍关于PHP $this变量一些理解,希望些文章对各位同学会有所帮助。
手册上的一个有意思的小示例。
http://www.php.net/manual/zh/language.variables.basics.php
代码如下 | 复制代码 |
$this = 'text'; // error echo $$name; |
在PHP的词法分析时,$this变量是符合其规则的,在语法解析生成中间代码时,PHP内核会根据变量类型在生成赋值的中间代码时判断是否为$this变量,如果是则报错。这里为什么要报错呢?因为this作为一个特殊的变量,在对象的成员方法等调用初始化时会将this变量添加到活动符号表。
在类的成员方法里面,可以用 ->(对象运算符):$this->property(其中 property 是该属性名)这种方式来访问非静态属性。
当一个方法在类定义内部被调用时,有一个可用的伪变量 $this。$this 是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象静态调用时也可能是另一个对象)。
在词法分析、语法分析并生成中间代码时,$this作为一个特殊的变量存在,特别是在生成中间代码时,代码中充斥着对于this的特殊处理。这些都是为后面的运行做准备,如识别标记出某处使用this变量,在存储opcode的zend_op_array结构体中专门有一个变量this_var标识是否有this变量。一个函数或一个类方法都会生成一个新的zend_op_array,在生成中间代码时,判断当前变量是否为this变量。
this变量在执行过程中会有两种存在状态,一种是全局传递的状态,存储在EG(This),一种是当前作用域状态,以this变量存储在EG(active_symbol_table)(当前执行环境的活动符号表)。
在我们执行一个 op_array 时,比如一个对象的方法,PHP内核会给这个 op_array 生成一个 zendexecutedata ,在生成初始化时,EG(This) 会添加到EG(active_symbol_table) 。
在方法调用过程中,如果有用到this变量,则会直接取EG(active_symbol_table)的值。
那么一个对象中的EG(This)在哪里初始化呢?
就EG(This)变量本身来说,在我们初始化PHP的执行环境时,它和其它全局变量(如EG(scope)等)一样都会被初始化为NULL。
对于一个对象来说,当我们创建了一个对象,调用时,PHP内核会将当前获得的对象直接赋值给EG(This),而这个当前获得的对象是在通过new操作生成对象时创建的对象本身。
如下这个简单示例:
代码如下 | 复制代码 |
class Foo { public $var = 10; function t() { echo $this->var; } function t2() { echo 33; } } $foo = new Foo(); $foo->t(); |
其主程序流程生成的中间代码如下:
代码如下 | 复制代码 |
function name: (null) number of ops: 8 compiled vars: !0 = $foo line # * op fetch ext return operands --------------------------------------------------------------------------------- 2 0 > NOP 15 1 ZEND_FETCH_CLASS 4 :1 'Foo' 2 NEW $2 :1 3 DO_FCALL_BY_NAME 0 4 ASSIGN !0, $2 16 5 ZEND_INIT_METHOD_CALL !0, 't' 6 DO_FCALL_BY_NAME 0 7 > RETURN 1this |
变量原始的对象值出生在 opcode NEW,经过了赋值(ASSIGN)后,在方法初始化时,将变量本身传递给执行环境的调用者,调用者又在执行调用(DO_FCALL_BY_NAME)时将变量传递给EG(This),当执行这个方法的op_array时,初始化当前作用域的环境(zend_execute_data)时,会将EG(This)作为$this变量添加到活动符号表,后续方法中的$this变量的使用就会直接取符号表的变量。
本文章来给各位同学介绍关于PHP的可变变量名使用方法,这个也是刚知道可变变量名了,大家一起来学习一下。
有时候可变的变量名会给编程带来很大的方便。也就是说变量名可以被动态的命名和使用。通常变量通过下面这样的语句来命名 :
代码如下 | 复制代码 |
<?php |
可变变量名指的是使用一个变量的值作为这个变量的名称。在上面的例子中,通过使用两个$符号,你可以把hello设置成一个变量的名称,就像下面那样。
代码如下 | 复制代码 |
<?php $$a = 'world'; ?> |
通过上面的两个语句,有两个变量被定义:变量$a,装的内容是”hello” 以及变量$hello,装的内容是 “world”。 于是,下面的语言:
代码如下 | 复制代码 |
<?php |
跟下面的语句的输出完全一致:
代码如下 | 复制代码 |
<?php |
它们都输出:hello world。
为了使用数组的可变变量名,你需要解决一个歧义问题。就是,如果你写$$a[1],解析器需要明白究竟你的意思是要把$a[1]当成一个变量,还是要把$$a当成变量、[1]指的是这个变量的索引。解决这个歧义问题的语法是:第一种情况使用${$a[1]},第二种情况使用${$a}[1]。
类属性也可以通过可变属性名来访问。可变属性名从产生调用所在的变量的访问范围内获取。例如,如果你的表达式是这样的:$foo->$bar,那么运行时将会在本地变量范围内寻找变量$bar,它的值将会做为$foo对象的一个属性名。如果$bar是个数组也可以使用。
例1 可变变量名
代码如下 | 复制代码 |
<?php 上面的例子将会输出下面的结果: I am bar. I am bar. |
警告
请注意,可变变量名不能用于PHP函数和类里的超级全局数组变量上。变量$this也是一个不能动态取名的特殊变量。
浅谈PHP可变变量安全
变变量是PHP一个非常方便的特性,手册里已经说了,可变变量的意思就是一个变量的变量名可以动态的设置!
那么变量的变量名可以动态设置会产生什么安全问题呢?下面来看看:
代码如下 | 复制代码 |
<?php $a = 'phpinfo'; $a(); ?> |
这段代码很容易理解,变量的类型是字符型phpinfo,变量动态加上了(),于是变量变成了phpinfo函数动态执行了!
按照同样的原理我们引用手册中可变变量的例子:
代码如下 | 复制代码 |
<?php $a = 'phpinfo'; ${$a()}; ?> $a() |
这个动态函数放入动态变量,当然我这个说法有点不专业,还是可变变量,我们会发现phpinfo函数还是执行了!
看过手册还有我给出的这个例子的话,大家一定觉得这个一点都不神奇,这就是PHP的语法特性,然后我们把这个东西再进化缩成一行:
代码如下 | 复制代码 |
<?php $a = "${${phpinfo()}}"; ?> |
这是一个2个嵌套的可变变量,我们只是按照上面一个例子将可变变量的内容自己填写进去了,实际上就是把某个函数赋给某个变量,所以phpinfo函数最终执行了,也就化成了各种漏洞和webshell的原型!
看到这里大家应该知道了,为什么当初大牛们要我去看PHP手册吧,然而本文到这里就结束了么,咱还漏了一点,大牛说了安全就是基础,咱其实还没把这个东西搞清楚,为什么前面例子的变量是用的单引号,而后面的最终的例子用的是双引号,如果你想到了这个问题,我觉得你做安全肯定非常有潜力,以后保不准就是一大牛!
PHP中单引号和双引号的区别还是和变量有关,来看下面的例子:
代码如下 | 复制代码 |
<?php $a = 'phpinfo()'; echo $a; //输出phpinfo()字符串 echo '$a'; //输出$a字符串 echo "$a"; //输出phpinfo()字符串 ?> |
双引号里的内容会再经过PHP的语法解析变量,而单引号里的内容就直接定性为字符串了!
所以本文到这里就真正结束了,于是大家应该也都明白了,当初牛人为什么和我说多看PHP手册和安全就是基础的深意。
因为最近在写一个日历的项目功能,所以自然而然想到了日志的存档,其实实现这样的功能也不是很难,首先要有一个日历的表单来直观显示日历,而处理日期的时间就交给了编程代码,比如PHP,对于要看之前写的文档,也就是将日历向前翻,那么就需要提交日历时间了,然后再交给表单来显示出来。
效果
下面是一个新手做的PHP日历功能,这里用一个文件将日历的功能给写出来了,文件不是很大,有注释,是一个简单的原理功能,接受部分都是由PHP来处理的,显示部分用的是表格,如果做PHP的日历项目可以直接进行二次开发即可使用。
代码如下 | 复制代码 |
<?php |
如何使用session
凡是与session有关的,之前必须调用函数session_start();
为session付值很简单,如:
程序代码
代码如下 | 复制代码 |
<?php |
在php4.2之后,可以为session直接付值:
程序代码
代码如下 | 复制代码 |
<?PHP |
取消session可以这样:
程序代码
代码如下 | 复制代码 |
<?php |
取消某个session变量在php4.2以上还有BUG.
读取 session
PHP 内置的 $_SESSION 变量可以很方便的访问设置的 session 变量。
例子:
代码如下 | 复制代码 |
<?php session_start(); echo "登记的用户名为:".$_SESSION["username"]; //输出 登记的用户名为:nostop ?> |
检查变量是否被登记为会话变量
session_is_registered
语法:boobean session_is_registered(string name);
这个函数可检查当前的session之中是否已有指定的变量注册,参数name就是要检查的变量名。成功则返回逻辑值true。
例子:
代码如下 | 复制代码 |
<?php session_start(); if(!session_is_registered("gender")){ //判断当前会话变量是否注册 session_register("gender"); //注册变量 } $gender="女"; echo $_SESSION['gender']; //女 ?> |
存取当前会话名称
session_name
语法:boolean session_name(string [name]);
这个函数可取得或重新设置当前session的名称。若无参数name则表示获取当前session名称,加上参数则表示将session名称设为参数name。
例子:
代码如下 | 复制代码 |
<?php $sessionName = session_name(); //取得当前 Session 名,默认为 PHPSESSID |
存取当前会话标识号
session_id
语法:boolean session_id(string [id]);
这个函数可取得或重新设置当前存放session的标识号。若无参数id则表示只获取当前session的标识号,加上参数则表示将session的标识号设成新指定的id。
设置 Session 的生存期
代码如下 | 复制代码 |
setcookie:向客户端发送一个 HTTP cookie。 |
session_set_cookie_params:设置 Session 的生存期的,该函数必须在 session_start() 函数调用之前调用。
如果客户端使用 IE 6.0 , session_set_cookie_params(); 函数设置 Cookie 会有些问题,所以我们还是手动调用 setcookie 函数来创建 cookie。
代码如下 | 复制代码 |
// 保存一天 |
设置 Session 文件的保存路径
session_save_path() :必须在 session_start() 函数调用之前调用。
代码如下 | 复制代码 |
<?php <?php $_SESSION['age']=23; //声明一个名为age的变量,并赋值 session_unregister('username'); //注销Session变量 unset($_SESSION['age']); //注销Session变量 |
注意:
1:在调用Session_Start()之前不能有任何输出.例如下面是错误的.
1行
2行 <?PHP
3行 Session_Start();//之前在第一行已经有输出
4行 .....
5行 ?>
==========================================
提示1:
凡是出现"........headers already sent..........",就是Session_Start()之前向浏览器输出信息.
去掉输出就正常,(COOKIE也会出现这种错误,错误原因一样)
提示2:
如果你的Session_Start()放在循环语句里,并且很难确定之前哪里向浏览器输出信息,可以用下面这种方法:
1行 <?PHP Ob_Start(); ?>
........这里是你的程序......
2:这是什么错误
Warning: session_start(): open(/tmpsess_7d190aa36b4c5ec13a5c1649cc2da23f, O_RDWR) failed:....
因为你没有指定session文件的存放路径.
解决方法:
(1)在c盘建立文件夹tmp
(2)打开php.ini,找到session.save_path,修改为session.save_path= "c:/tmp"
相关文章
- 这篇文章主要介绍了go浮点数转字符串保留小数点后N位解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-05-11
- 浮点数就是有很我小数的那种并且不只单纯了数字了,而小编在用支付接口时就碰到浮点数丢失的问题,下文一起来看看问题解决方法. 先看下面这段代码: $f = 0.57; echo...2016-11-25
基于C++浮点数(float、double)类型数据比较与转换的详解
本篇文章是对C++中浮点数(float、double)类型数据比较与转换进行了详细的分析介绍,需要的朋友参考下...2020-04-25php FILTER_VALIDATE_FLOAT 浮点数验证
filter_validate_float 过滤器把值作为浮点数来验证。 */ $var=12.3; var_dump(filter_var($var, filter_validate_float)); //float(12.3) /* 非负浮点数(正浮点数...2016-11-25- 本文介绍了WebStorm 遇到的问题总结,非常实用,有兴趣的同学可以参考一下本文 最近自己WebStorm用得多一点了和android studio一样,同样是IDEA的ide(记得自己还是eclip...2017-07-06
- 这篇文章介绍了浮点数在计算机中是如何存储的,讲解的比较详细,有需要的朋友可以参考一下。...2020-04-25
- 本篇文章是对C++中浮点数无效值定义与判定进行了介绍,需要的朋友参考下...2020-04-25
- 这篇文章主要介绍了golang 比较浮点数的大小方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-01
- 在php中浮点数计算通常我们会得不到自己想要的结果了,这个到底是什么原因呢,下面我们来分析问题的同时也给各位朋友整理了一些比较好用的实例。 如果用php的+-*/计...2016-11-25
- 语法 round(x,prec)参数 描述 x 可选。规定要舍入的数字。 prec 可选。规定小数点后的位数。 说明 返回将 x 根据指定精度 prec (十进制小数点后数字的数目)进行四...2016-11-25
- 这篇文章主要介绍了Python如何执行精确的浮点数运算,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-08-01
- Php部分常见问题总结-转载 1:为什么我得不到变量 我在一网页向另一网页POST数据name,为什么输出$name时却得不到任何值? 在PHP4.2以后的版本中register_global默...2016-11-25
- php中浮点数运算常见问题有哪些呢,今天我们就一起来看看这些关于php中浮点数运算常见问题总结吧,具体的如下文介绍. 本文实例分析了php中让人头疼的浮点数运算。...2016-11-25
- 在应用开发中有不少朋友会碰到session无效了或session丢失问题,下面我来整理一些导致PHP Session丢失无效问题与解决方法。 前两天玩了一下云边的轻博客,觉得东西...2016-11-25
- 这篇文章主要介绍了对浮点数保存指定位小数。比如, 1.123456. 要保存1位小数,,调用方法后, 保存的结果为: 1.1。 再比如,1.98765, 保存2位小数的结果为: 2.00,需要的朋友可以参考下...2020-04-25
- 下文来为各位介绍Php处理浮点数的问题了,如果各位在使用过程中碰到这些问题我们可以一起来看看,希望文章对各位有帮助 公司要对产品价格做调整,因为做的外贸商城,所以...2016-11-25
- 本文章收藏了php开发中常常会碰到的一些疑惑或一些小问题,大家可参考一下。 上面一些函数之间的区别, 1.isset()和empty()的区别 两者都是测试变量用的。但是isset...2016-11-25
- 本篇文章是对C++中浮点数无效值的定义与无效值的判定进行了详细的分析介绍,需要的朋友参考下...2020-04-25
- 这篇文章主要介绍了C#浮点数的表示和基本运算,需要的朋友可以参考下...2020-06-25
- 本文通过具体的示例给大家演示了下C#中浮点数运算所遇到的问题及解决方法,有需要的小伙伴可以参考下...2020-06-25