美文网首页
php扩展 求解一元二次方程

php扩展 求解一元二次方程

作者: 巩文 | 来源:发表于2019-12-22 23:40 被阅读0次

    第一步 生成扩展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

    相关文章

      网友评论

          本文标题:php扩展 求解一元二次方程

          本文链接:https://www.haomeiwen.com/subject/gdmanctx.html