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服务),通过浏览器验证

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);
}
/* }}}*/
...

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

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
';
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扩展版

';
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代码版

 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 '
';
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

你可能感兴趣的:(php扩展 求解一元二次方程)