惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
量子位
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
爱范儿
爱范儿
博客园 - 【当耐特】
Vercel News
Vercel News
S
SegmentFault 最新的问题
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
博客园 - 叶小钗
博客园_首页
V
Visual Studio Blog
宝玉的分享
宝玉的分享
B
Blog
MyScale Blog
MyScale Blog
C
Check Point Blog
博客园 - 三生石上(FineUI控件)
L
LangChain Blog
V
V2EX

风雪之隅

Yac 2.4.0发布 - 小值读取性能提升64% 用Yac给WordPress做缓存:比Memcached快19% Laruence Laruence Laruence Laruence Laruence 深入理解PHP7内核之OBJECT - 风雪之隅 PHP 8新特性之Attributes(注解) - 风雪之隅 博客迁移到腾讯云 - 风雪之隅 在Qcon 2015 北京上的演讲PPT - PHP7 Yar-2.1 新功能介绍 - 风雪之隅 Yaf and Phalcon, which is faster? HTTPOXY漏洞说明 - 风雪之隅 一个关于Zend O+的小分享 - 风雪之隅 在PHP中使用协程实现多任务调度 - 风雪之隅 Curl的毫秒超时的一个"Bug" - 风雪之隅 PHP8.0的Named Parameter - 风雪之隅 关于PHP,关于Realsee - 风雪之隅 PHP8新特性之match表达式 - 风雪之隅 PHP 8新特性之JIT简介 - 风雪之隅 使用SSE2指令高效实现strtolower - 风雪之隅 使用OSC52实现iTerm2远程pbcopy - 风雪之隅 Yaf 3.2 发布 - 风雪之隅 使用PHP Socket开发Yar TCP服务 - 风雪之隅 Yac 2.1 升级说明 - 风雪之隅 Yaf-3.1 10%性能提升版 - 风雪之隅 Yaconf-1.1 40%速度提升版 - 风雪之隅 PHP FFI详解 - 一种全新的PHP扩展方式 - 风雪之隅 使用SSE2指令集加速字符替换 - 风雪之隅
PHP_INT_MIN 和 -9223372036854775808 - 风雪之隅
laruence · 2020-02-28 · via 风雪之隅

刚刚吃饭的时候想说今天再写点啥? 突然想起来前几天有人在微博上评论我的一个PHP的面试题:

var_dump(PHP_INT_MIN);
var_dump(-9223372036854775808);

输出一样么? 如果不一样为什么?

我认为这样的题目作为PHP面试题并不合适。 不过作为一个有趣的知识点,我今天就说说这个小问题吧。

我们知道64位的整数的表值范围是-9223372036854775808 到 9223372036854775807.

在64位系统上PHP内部是使用有符号的64位整形来表示IS_LONG, 分别有俩个常量来表示这俩个值, 分别是PHP_INT_MIN和PHP_INT_MAX.

在64位平台上,PHP_INT_MIN就等于-9223372036854775808,那题目的意思是啥呢? 我们输出下看看:

int(9223372036854775807)
float(-9.2233720368548E+18)

输出果然不一样,那是什么造成了这个差异呢?

在PHP编译器处理输入文件输入的时候,对于负数字面量它的处理方式是:

-{LNUM}
   => '-' expr { $$ = zend_ast_create(ZEND_AST_UNARY_MINUS, $2); }
   => UNARY_MINUS: 0 - expr 

也就是,首先把负号后面的数字作为一个整形接受进来,然后在把它求负。

于是这就造成了这个问题, 开头我们说了64位的最大正表值是9223372036854775807,那当PHP处理-9223372036854775808的时候, 9223372036854775808 超出了64位整形的最大正表值范围,PHP没有办法用一个有符号64位整形存储它,于是只能把它自动转成了DOUBLE类型。 于是接下来....

其实在C语言中如果你写下如下的代码:

int main() {
    long a = -9223372036854775808;

    return 0;
}

你应该会收到类似如下的警告:

warning: integer constant is so large that it is unsigned

也就是说,你直接写9223372036854775808的话,C编译器会提示你这个数字太大了,应该用unsigned才能表示,并默认给你转成了unsigned long,然后再求负。

当然,也可以强制通过指明UL来避免这个警告从而进行直接赋值,但更多的时候,为了显示的表示此处有坑,大家一般都会这么写(比如在ubuntu的/usr/include/stdint.h):

#define INT64_MIN  (-__INT64_C(9223372036854775807)-1)

也就是通过一个表达式来代替直接写一个字面量, 对应的,我们也可以通过在脚本中这么写:

$min = -9223372036854775807 - 1;

来避免这个限制,就能正常表达PHP_INT_MIN啦。 其实在PHP7之前并没有定义PHP_INT_MIN的时候,我们也是这么习惯写的,比如PHP源代码中的一些测试脚本中(ext/date/tests/date_create-relative.phpt):

if (!defined('PHP_INT_MIN')) {
    define('PHP_INT_MIN', intval(-PHP_INT_MAX - 1));
}