php扩展 求解一元二次方程

第一步 生成扩展demo Runing起来

生成扩展demo

我们以php-7.4.1版本为例。

进入 cd php-7.4.1/ext 此目录,有一个名为 ext_skel.php。我们用此脚本生在扩展demo步骤如下

./ext_skel.php --ext gwalker

这样就在 ext目录下生成 gwalker扩展目录,目录内容如下:

[root@gw gwalker]# ls
config.m4  config.w32  gwalker.c  php_gwalker.h  tests

接下来进行编译,安装到php扩展中

[root@gw gwalker]# phpize
Configuring for:
PHP Api Version:         20131106
Zend Module Api No:      20131226
Zend Extension Api No:   220131226
./configure --with-php-config=/data/php/bin/php-config
make && make install
修改php.ini 把生成的so加关联到扩展中去
extension=/data/php/lib/php/extensions/debug-non-zts-20190902/gwalker.so

这样就把gwalker扩展加到php环境中去了。可以通过cli命令验证查看

./php -m | grep gwalker
gwalker

也可以重新启动php-fpm(或php内置web服务),通过浏览器验证

<?php
    phpinfo();
new.png

运行demo扩展

打开gwalker.c源码文件阅读代码发现生成的demo给咱们实现好了,gwalker_test1()与gwalker_test2()函数。

...
/* {{{ void gwalker_test1()
 */
PHP_FUNCTION(gwalker_test1)
{
        ZEND_PARSE_PARAMETERS_NONE();

        php_printf("The extension %s is loaded and working!\r\n", "gwalker");
}
/* }}} */

/* {{{ string gwalker_test2( [ string $var ] )
 */
PHP_FUNCTION(gwalker_test2)
{
        char *var = "World";
        size_t var_len = sizeof("World") - 1;
        zend_string *retval;

        ZEND_PARSE_PARAMETERS_START(0, 1)
                Z_PARAM_OPTIONAL
                Z_PARAM_STRING(var, var_len)
        ZEND_PARSE_PARAMETERS_END();

        retval = strpprintf(0, "Hello %s", var);

        RETURN_STR(retval);
}
/* }}}*/
...

那咱们测试下这两个函数,是否能够正常运行

<?php
    gwalker_test1();
    echo "\n";
    echo gwalker_test2('gongwen');
The extension gwalker is loaded and working!
Hello gongwen

第二步 编码一元二次方程求解函数扩展

函数功能如下:
求解 ax^2 + bx +c = 0;
如果a为0则降级为一元一次方程求解。否则有无解的话返回布尔false,一个解返回数组[x],两个解返回数组[x1,x2]

编码求解函数 getSolutionOVQE

注 OVQE 为Quadratic equation of one variable

PHP_FUNCTION(getSolutionOVQE)
{
    double a = 0;
    double b = 0;
    double c = 0;

    // 定义x1,x2用来保放一元二次方程的两个解
    double x1 = 0;
    double x2 = 0;

    // detal 记录 b^2 - 4ac的值
    double detal = 0;

    // =========参数接收处理阶段 begin ===============
    ZEND_PARSE_PARAMETERS_START(2, 3) //接收参数,最少两个参数,最多3个参数
        Z_PARAM_DOUBLE(a)                 // 接收第一参数,赋a
        Z_PARAM_DOUBLE(b)                 // 接收第二参数,赋b
        Z_PARAM_OPTIONAL                  // 表示后面的参数为选填项
        Z_PARAM_DOUBLE(c)             // 接收第二参数,赋c
        ZEND_PARSE_PARAMETERS_END();
    // =========参数接收处理阶段 end ===============


    // 如果a与b两个系统数都为0,则返回false
    if (a == 0 && b == 0)
    {
        RETURN_FALSE;
    }
    
    // 扩展开发通过return_value这个变量设置方法的返回值
    array_init(return_value);
    
    // 如果a=0 ,则降级为一元一次方程求解
    if (a == 0)
    {
        x1 = -1 * (c/b);
        add_index_double(return_value, 0, x1);
        return;
    }
    detal = pow(b, 2) - 4 * a * c;

    if (detal == 0)
    {
        x1 = (-b + sqrt(detal)) / (2 * a);
        add_index_double(return_value, 0, x1);
        return;
    }
    else if (detal > 0)
    {
        x1 = (-b + sqrt(detal)) / (2 * a);
        x2 = (-b - sqrt(detal)) / (2 * a);
        add_index_double(return_value, 0, x1);
        add_index_double(return_value, 1, x2);
        return;
    }
    // 都不符合是返回false
    RETURN_FALSE;
}
注册 getSolutionOVQE 函数
static const zend_function_entry gwalker_functions[] = {
        PHP_FE(gwalker_test1,           arginfo_gwalker_test1)
        PHP_FE(gwalker_test2,           arginfo_gwalker_test2)
        PHP_FE(getSolutionOVQE,         NULL)
        PHP_FE_END
};

重新编译,测试

make && make install
<?php
$v = getSolutionOVQE(0,1,2);
echo '<pre>';
var_dump($v);

$h = getSolutionOVQE(1,2,1);
var_dump($h);


$h = getSolutionOVQE(1,-7,12);
var_dump($h);


$h = getSolutionOVQE(5,7,1);
var_dump($h);

$h = getSolutionOVQE(0,0,0);
var_dump($h);

$h = getSolutionOVQE(2,1,20);
var_dump($h);


$h = getSolutionOVQE(90,100,25);
var_dump($h);

$h = getSolutionOVQE(0,100,25);
var_dump($h);
exit;

输出如下:

array(1) {
  [0]=>
  float(-2)
}
array(1) {
  [0]=>
  float(-1)
}
array(2) {
  [0]=>
  float(4)
  [1]=>
  float(3)
}
array(2) {
  [0]=>
  float(-0.16148351928655)
  [1]=>
  float(-1.2385164807135)
}
bool(false)
bool(false)
array(2) {
  [0]=>
  float(-0.37987346332398)
  [1]=>
  float(-0.73123764778713)
}
array(1) {
  [0]=>
  float(-0.25)
}

附php代码版求一元二次方程

function php_getSolutionOVQE($a,$b,$c=0){
        $x1=0;
        $x2=0;
        $detal=0;
        if($a==0 && $b==0){
                return false;
        }
        if($a==0){
                $x1 = -1 * ($c/$b);
                return [$x1];
        }
        $detal = pow($b,2) - 4*$a*$c;

        if($detal == 0){
                $x1 = (-1*$b + sqrt($detal)) / (2 * $a);
                 return [$x1];
        }else if($detal > 0){
                $x1 = (-1*$b + sqrt($detal)) / (2 * $a);
                $x2 = (-1*$b - sqrt($detal)) / (2 * $a);
                return [$x1,$x2];
        }
        return false;
}

性能比较

现在分别进行100万次的一元二次方程求解。看下所用耗时

c扩展版如下(执行5次,用时记录如下):

use time : 0.993971824646 s
use time : 0.99442791938782 s
use time : 0.99134087562561 s
use time : 0.99235987663269 s
use time : 0.99243712425232 s

php代码版如下(执行5次,用时记录如下):

use time : 2.2686109542847 s
use time : 2.2673828601837 s
use time : 2.2710490226746 s
use time : 2.3082909584045 s
use time : 2.2692041397095 s

观察结果性能提升了2.2倍

注 性能测试代码如下:

c扩展版

<?php
$start_time = microtime(true);
echo '<pre>';
for($i = 1;$i<=1000000;$i++){
        $a = $i+2;
        $b = $i*3;
        $c = $i+6;
        $re = getSolutionOVQE($a,$b,$c);
        //var_dump($re);
}
$end_time = microtime(true);
echo 'use time : '.($end_time-$start_time).' s';
exit;

php代码版

<?php
function php_getSolutionOVQE($a,$b,$c=0){
        $x1=0;
        $x2=0;
        $detal=0;
        if($a==0 && $b==0){
                return false;
        }
        if($a==0){
                $x1 = -1 * ($c/$b);
                return [$x1];
        }
        $detal = pow($b,2) - 4*$a*$c;

        if($detal == 0){
                $x1 = (-1*$b + sqrt($detal)) / (2 * $a);
                 return [$x1];
        }else if($detal > 0){
                $x1 = (-1*$b + sqrt($detal)) / (2 * $a);
                $x2 = (-1*$b - sqrt($detal)) / (2 * $a);
                return [$x1,$x2];
        }
        return false;
}

$start_time = microtime(true);
echo '<pre>';
for($i = 1;$i<=1000000;$i++){
        $a = $i+2;
        $b = $i*3;
        $c = $i+6;
        $re = php_getSolutionOVQE($a,$b,$c);
        //var_dump($re);
}
$end_time = microtime(true);
echo 'use time : '.($end_time-$start_time).' s';
exit;

代码地址

https://github.com/gongwalker/getSolutionOVQE

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

推荐阅读更多精彩内容

  • 说明本次redis集群安装在rhel6.8 64位机器上,redis版本为3.2.8,redis的gem文件版本为...
    读或写阅读 14,588评论 3 9
  • 使用PHP扩展的原因: 准备工作 一:了解PHP源码目录 网上下载下来PHP 5.4版本源代码,目录结构如下: 二...
    Chuck_Hu阅读 3,693评论 1 17
  • 前言 本文主要简单介绍(本人水平有限,也是边学习边写)一下PHP的生命周期,扩展的开发步骤,以及扩展开发一些常用的...
    痞子与PHP阅读 718评论 2 6
  • 一个没水没电的上午在家闲的帮弟弟做了一份手抄报 还给一个两年前收到的玫瑰做了个包装嘻嘻嘻(因为是最喜欢人送的 所以...
    娜朵拉阅读 113评论 0 1
  • 夏河的天空,湛蓝的让人睁不开眼,原来深蓝色也会刺人的眼睛。她们相遇在这里,L和一个女孩。以深蓝色的天空为背景。红色...
    原木C阅读 407评论 0 0