php逆整数输出不输出0,PHP7下除0返回NAN错误

博客介绍了在PHP7和PHP5中处理除数为0时的不同行为,以及由此引发的问题。在PHP5中,除数为0会返回false,而在PHP7中则返回NAN。这个问题在处理数据归一化时导致了NAN的出现,并影响了JSON编码和MySQL数据存储。作者强调了代码审查、问题复现、环境一致性以及了解依赖方变更的重要性。
摘要由CSDN通过智能技术生成

线上的一个项目,过去一周数据展示异常。排查的过程中发现PHP7和PHP5的一个有趣的差异,特记录下来。

为了尽量把问题描述清楚,单独抽象了一个极简模型:电视节目排行榜,每个电视节目有4项数据(阅读数、互动数、搜索数、播放数),假如数据已经生成好,要求根据这4项数据制作一个Top100榜单,显示节目排名和分值(0-100之间)

模拟数据如下(真实数据可能来自数据部门,通过HTTP接口获取JSON数据,或者MQ获取)

$data = [

[

'id' => 1,

'name' => '如懿传',

'read_count' => 11714096,

'interactive_count' => 230,

'search_count' => 1078,

'play_count' => 20,

],

[

'id' => 2,

'name' => '甄嬛传',

'read_count' => 21714096,

'interactive_count' => 410,

'search_count' => 900,

'play_count' => 9,

],

[

'id' => 3,

'name' => '芈月传',

'read_count' => 8018618,

'interactive_count' => 333,

'search_count' => 1700,

'play_count' => 2,

],

];

算法:

0、对每一个节目每个维度的数据进行归一化处理A1, B1, C1, D1。

1、定义每个维度的权重w1, w2, w3, w4(w1 + w2 + w3 + w4 = 1)。

2、计算每个节目的分值score。每个维度归一化后的数据 * 相应权重求和(score = A1 * w1 + B1 * w2 + C1 * w3 + D1 * w4)。

3、按分值排序。

4、计算排名。

计算归一值的方法

/**

* 计算归一值

* @param $ini int 当前值

* @param $max int 当前维度最大值

* @param $min int 当前维度最小值

*

* @return float 分值

*/

public static function normal($ini, $max, $min) {

$max = log(1 + $max);

$min = log(1 + $min);

return (log(1 + $ini) - $min) / ($max- $min);

}

计算分值

public static function get_score($data, $weight) {

$data['read'] = self::normal($data['read_count'], $data['read_max'], $data['read_min']);

$data['interactive'] = self::normal($data['interactive_count'], $data['interactive_max'], $data['interactive_min']);

$data['search'] = self::normal($data['search_count'], $data['search_max'], $data['search_min']);

$data['play'] = self::normal($data['play_count'], $data['play_max'], $data['play_min']);

$add = $data['read'] * $weight['w1'] + $data['interactive'] * $weight['w2'] +

$data['search'] * $weight['w3'] + $data['play'] * $weight['w4'];

$score = log($add + 1, 2);

return $score;

}

以上是部分实现,在归一化的时候,max和min一般不会都为0, 确实在线上跑了2年也没出问题,但是前不久,数据依赖方做了调整play这一项数据全部为0,导致方法normal()中除数为0,返回NAN,get_score()也返回NAN。根本原因还是没有检查除数为0的情况。

事后验证对比发现,

PHP5下除数为0返回false, PHP7下除数为0返回NAN。

PHP中1 + false = 1,1 + NAN = NAN;

PHP中json_encode($data),$data中值包含NAN将返回false。

PHP中的NAN入到MySQL中显示为0。

echo date('Y-m-d H:i:s') . PHP_EOL;

echo "PHP版本: " . phpversion() . PHP_EOL;

$data = 0 / 0;

$res = 100 + $data;

$count = [

'id' => 1,

'read_count' => 100,

'score' => NAN,

];

var_dump($data, $res, $count, json_encode($count), 2333);die;

// PHP5返回结果begin

2018-09-24 09:34:18

PHP版本: 5.6.9-0+deb8u1

bool(false)

int(100)

array(3) {

["id"]=>

int(1)

["read_count"]=>

int(100)

["score"]=>

float(NAN)

}

bool(false)

int(2333)

PHP Warning: Division by zero in /usercode/file.php on line 5

// PHP7下返回结果

2018-09-24 09:33:32

PHP版本: 7.0.0-dev

Warning: Division by zero in /usercode/file.php on line 5

float(NAN)

float(NAN)

array(3) {

["id"]=>

int(1)

["read_count"]=>

int(100)

["score"]=>

float(NAN)

}

bool(false)

int(2333)

总结:

0、浏览代码的时候一定要看完整,不要漏了某一行,导致逻辑看不懂。

1、解决问题的正确方式,复现现象,在有问题的代码中加日志。加日志的时候,缩小日志的记录,方便查看定位问题。切记不要猜测,有些问题的原因根本是猜不到的。【谁会想到PHP7下0 /0会返回NAN,谁能想到NAN + 1 = NAN,谁能想到json_encode()的数组中带NAN返回异常,谁能想到NAN入到MySQL中为0 】

2、时刻提醒自己线上环境和验证环境是否完全一直。最好开发环境和生产环境一直,起码PHP版本要一致。

3、长期运行稳定的代码突然出问题,一定要了解下其他方近期做了什么调整,依赖方上下线了什么,自己上线了什么,运营调整了什么运维调整了什么。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,您想了解如何在 C 语言中输出整数时左端使用 0 补齐?这可以通过 printf 函的格式控制符来实现。可以使用 %0Nd 的格式控制符,其中 N 是输出宽度,表示输出字的位;d 表示输出的类型为十进制整数。例如,如果要输出宽度为 5 的整数,可以使用 %05d 的格式控制符。这将在左端使用 0 补齐,确保输出值的位达到 5 位。希望这能解决您的问题。 ### 回答2: 在C语言中,我们可以使用格式控制符来实现整数的左端补齐。其中,"%0d"可以用于输出十进制整数,"%0o"可以用于输出八进制整数,"%0x"可以用于输出十六进制整数。 例如,我们要输出一个整数28的八进制表示,可以使用以下代码: ```c int num = 28; printf("八进制表示为:%04o\n", num); ``` 在上述代码中,"%04o"中的"0"表示用0来填充左侧空白位置,"4"表示总共4位,如果实际位小于4,则会在左侧用0来补齐。因此输出结果为:"八进制表示为:0034",其中前面的两个0就是通过左端补齐实现的。 同样的道理,如果我们要输出28的十六进制表示,可以使用以下代码: ```c int num = 28; printf("十六进制表示为:%02x\n", num); ``` 在上述代码中,"%02x"中的"0"表示用0来填充左侧空白位置,"2"表示总共2位,因此输出结果为:"十六进制表示为:1c",其中前面的0就是通过左端补齐实现的。 综上所述,在C语言中可以使用格式控制符实现整数输出左端用0补齐。 ### 回答3: 在C语言中,我们可以使用printf函来控制整数输出格式。如果我们想要在输出整数时使用0来补齐左端,可以使用printf函中的格式控制符来实现。 具体来说,我们可以使用%0d格式控制符来输出整数并使用0来补齐左端。这里的d表示输出一个十进制整数,并且通过0来补齐左端。假设我们要输出一个整数num,使用%0d格式控制符的语法如下: printf("%0d", num); 例如,如果我们要输出整数10,使用%0d格式控制符输出的结果就是"10",左端会用0来补齐。同样地,如果我们要输出整数100,使用%0d格式控制符输出的结果就是"100",左端同样会用0来补齐。 总结起来,要在C语言中使用0来补齐整数的左端输出,我们需要使用%0d格式控制符,然后将要输出整数作为参传递给printf函即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值