IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> PHP中操作任意精度大小的GMP扩展学习 -> 正文阅读

[PHP知识库]PHP中操作任意精度大小的GMP扩展学习

PHP中操作任意精度大小的GMP扩展学习

对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了。其实,这也是一种精度越界之后产生的精度丢失问题。在我们的 PHP 代码中,最大的整数非常大,我们可以通过 PHP_INT_MAX 来查看。不过,当整数超过一定的位数之后,就会使用科学计数法来显示了,这个可不是我们想要的结果。别着急,GMP 扩展就是专门用来应对这种情况的。

GMP 扩展是随 PHP 源码包一起发布的,在安装扩展之前需要系统环境中先安装 gmp-devel ,在 CentOS 中直接 yun install gmp-devel 就可以了。

超大数字的精度丢失问题

我们先来看看直接打印输出超大的数字会发生什么。

echo?PHP_INT_MAX;?//?92233720368547758071.2312312312312E+26

$a?=?123123123123123123123123123;
echo?$a,?PHP_EOL;?//?1.2312312312312E+26
echo?$a?+?1,?PHP_EOL;?//?1.2312312312312E+26

可以看到,显示的结果都是科学计数法的形式了。而且对于简单的运算操作来说,也基本看不到有什么区别了。就像我们最后给 $a + 1 的情况,它和原始的数据展示 出来的结果是一样的。

$b?=?gmp_init("123123123123123123123123123");
echo?$b,?PHP_EOL;?//?123123123123123123123123123
echo?gmp_add($b,?1),?PHP_EOL;?//?123123123123123123123123124

当我们使用 GMP 扩展后,就可以使用 gmp_init() 来实例化这样的超大数字。打印的结果还是标准的数字格式。不过,这里需要注意的是,这个扩展其实是将我们要操作的这种超大的数字转换成了字符串来表示。

gmp_add() 是 GMP 的加法操作函数,非常简单,就是两个参数进行相加,然后返回的依然是一个 GMP 对象。

var_dump($b);
//?object(GMP)#1?(1)?{
//?????["num"]=>
//?????string(27)?"123123123123123123123123123"
//???}
echo?$b?+?1,?PHP_EOL;?//?123123123123123123123123124

通过打印 gmp_init() 返回的 $b 对象就可以看出来。它里面的内容其实是一个字符串了。同时,这个对象还重写了 __toString() 方法,所以我们可以直接 echo 它。另外,GMP 对象还重载了运算操作符,所以直接针对 GMP 对象进行日常的操作符运算也是没有问题的。

简单运算操作

除了重载的操作符之外,GMP 扩展也提供了一系列的运算操作函数,就像我们上面已经见过了 gmp_add() 一样。

echo?gmp_sub($b,?1),?PHP_EOL;?//?123123123123123123123123122
echo?gmp_mul($b,?2),?PHP_EOL;?//?246246246246246246246246246
echo?gmp_div("123123123123123123123123123",?3),?PHP_EOL;?//?41041041041041041041041041
echo?gmp_mod($b,?5),?PHP_EOL;?//?3

这四个分别就是 减 、乘 、除 、余 的计算。非常地简单,这里也就不多说了。在这里需要注意的一点是,它们接收的参数可以是 int 类型,也可以是 字符串 类型。就和 gmp_init() 接收的参数一样。

echo?gmp_abs("-123123123123123123123123123"),?PHP_EOL;?//?123123123123123123123123123
echo?gmp_pow($b,?3),?PHP_EOL;?//?1866460784838622135378351047886265184644645186267890058355382138624840786461867
echo?gmp_sqrt($b),?PHP_EOL;?//?11096085937082

这三个函数分别是取绝对值、乘方、二次方根的计算函数。和普通的 Math 计算函数都是类似的。

位操作

GMP 扩展还可以方便地对数据进行位操作以及二进制操作。比如位操作中的 与 、或 、异或。

echo?gmp_and($b,?"2222222222"),?PHP_EOL;?//?2151965570
echo?gmp_or($b,?"2222222222"),?PHP_EOL;?//?123123123123123123193379775
echo?gmp_xor($b,?"3333333333"),?PHP_EOL;?//?123123123123123120012088038

还可以将一个数字转换成二进制格式导出。

echo?gmp_export($b),?PHP_EOL;?//?e�U��(c�O�

当然,也有对应的从二进制导入的函数,这里我们就不做演示了。大家可以自己在文档中查找相应的函数测试了解。

$pop1?=?gmp_init("10000101",?2);?//?3
echo?gmp_popcount($pop1),?PHP_EOL;
$pop2?=?gmp_init("11111110",?2);?//?7
echo?gmp_popcount($pop2),?PHP_EOL;

gmp_popcount() 函数用于获取二进制表示的字符中的 1 的数量。比如这段测试代码中返回的结果。

$s1?=?gmp_init("10111",?2);
echo?gmp_scan0($s1,?0),?PHP_EOL;?//?3

$s2?=?gmp_init("101110000",?2);
echo?gmp_scan0($s2,?0),?PHP_EOL;?//?0

$s1?=?gmp_init("10111",?2);
echo?gmp_scan1($s1,?0),?PHP_EOL;?//?0

$s2?=?gmp_init("101110000",?2);
echo?gmp_scan1($s2,?0),?PHP_EOL;?//?4

gmp_scan0() 和 gmp_scan1() 函数则是分别查找第一个出现的 0 或 1 的位置。它的第二个参数是指明从哪个位置开始查找。另外,它们查找的方向都是从右向左开始查找,并且是从下标 0 的位置开始的哦。

其它运算操作

生成随机数

echo?gmp_random_range("10000000000000",?"99999999999999999"),?PHP_EOL;?//?83490559526159213
//?12500000000
echo?gmp_random_bits(99999),PHP_EOL;?//?289814632948807684404778811091812938699609………………

就和普通的生成随机数的函数一样,只不过 GMP 扩展库下面的这两个函数能够生成的数字范围更大,而且返回的也是 GMP 对象的格式。对于 gmp_random_bits() 来说,最大的范围是 12500000000 ,我的机子如果使用这个随机因子的话直接就会报超出内存了。而使用 99999 这个随机因子生成的随机数字也已经非常大了,大家可以自己尝试一下。

阶乘

这个是普通的 Math 库中所没有的函数。直接帮我们计算阶乘的结果,不用自己写算法了哦。

echo?gmp_fact(5),?PHP_EOL;?//?120????5*4*3*2*1=120
echo?gmp_fact(50),?PHP_EOL;?//?30414093201713378043612608166064768844377641568960512000000000000?50*49*48…………*2*1

素数

除了阶乘之外,GMP 还提供了非常高大上的直接获取和判断素数的函数。一般来说,素数(质数)也是面试中非常常见的算法题目,我们在面试的时候还是要掌握自己手写的能力,但是手写完之后能和面试官说一下 GMP 中已经有现成的函数了相信也会带来一些加分。

echo?gmp_nextprime(10),?PHP_EOL;?//?11
echo?gmp_nextprime(1000),?PHP_EOL;?//?1009
echo?gmp_prob_prime(6),?PHP_EOL;?//?0
echo?gmp_prob_prime("1111111111111111111"),?PHP_EOL;?//?1
echo?gmp_prob_prime(7),?PHP_EOL;?//?2

gmp_nextprime() 是获取指定数字之后的下一个素数是多少。gmp_prob_prime() 则是判断给写的数字是否是素数,它有三种结果,0 表示不是素数,1 表示可能(疑似)素数,2 表示确定是素数。

数据的符号信息

echo?gmp_sign("500"),?PHP_EOL;?//?1
echo?gmp_sign("-500"),?PHP_EOL;?//?-1
echo?gmp_sign("0"),?PHP_EOL;?//?0

最后这个 gmp_sign() 函数用来表示给定数据的符号信息,也就是正负数。它也是三种结果,1 表示正数,-1 表示负数,0 表示 0 。为什么会有一个特殊的 0 存在呢?因为 0 即不是正数也不是负数呀,它本身就是一个特殊的存在。

总结

关于 GMP 扩展还有很多方法并没有一一列举出来,在这里只是挑选了一些比较常用的内容给大家介绍一下。虽说是刷文档,但也不能直接照搬文档过来,所以更多的内容大家还是自行去文档中查阅,我们学习的目的主要就是知道有这么个东西,不至于在真实的业务需求中踫到了相关的内容时抓瞎。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/8.PHP中操作任意精度大小的GMP扩展学习.php

参考文档:

https://www.php.net/manual/zh/book.gmp.php

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-25 11:59:32  更:2021-08-25 12:01:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 4:14:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码