| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850 | <?php/** * Math.php  UTF-8 * 数字处理类 * * @date    : 2018/1/6 16:52 * * @license 这不是一个自由软件,未经授权不许任何使用和传播。 * @author  : guxiannong <gxn@huosdk.com> * @version : HUOSDK 8.0 */namespace huolib\tool;class Math {    const DIV_N = 15;    /**     * 进一法强制保留两位小数     *     * @param $num     *     * @return mixed|string     */    public static function showFloatTwoMax($num) {        return self::accMul(ceil(self::accMul($num, 100)), 0.01);    }    /**     * 两数相加     *     * @param     $a     * @param     $b     *     * @param int $decimals 保留小数位     *     * @return string     */    public static function addNum($a, $b, $decimals = 2) {        if (!$decimals) {            $decimals = 2;        }        $_n = self::getMaxPoint($a, $b, $decimals);        return number_format((number_format($a, $_n, '.', '') + number_format($b, $_n, '.', '')), $decimals, '.', '');    }    /**     * 两数相加 可正数、负数、小数     *     * @param $a     * @param $b     *     * @return string     */    public static function addBigNum($a, $b) {        $_first_a = substr($a, 0, 1);        $_first_b = substr($b, 0, 1);        if ('-' == $_first_a && '-' == $_first_b) {            return '-'.self::realBigNum(substr($a, 1), substr($b, 1));        } else if ('-' == $_first_a && $_first_b != '-') {            return self::addBigMic($b, substr($a, 1));        } else if ('-' == $_first_b && $_first_a != '-') {            return self::addBigMic($a, substr($b, 1));        } else if ('-' != $_first_b && $_first_a != '-') {            return self::realBigNum($a, $b);        }    }    /**     * 两个大数相加 可带小数     *     * @param $a     * @param $b     *     * @return string     */    public static function realBigNum($a, $b) {        $_la = '';        $_la_l = 0;        if (strpos($a, '.')) {            $_arr_a = explode('.', $a);            if (isset($_arr_a[1])) {                $_la_l = strlen($_arr_a[1]);                $_la = $_arr_a[1];            }            $_la_n = $_arr_a[0];        } else {            $_la_n = $a;            $_la = '';            $_la_l = 0;        }        $_lb = '';        $_lb_l = 0;        if (strpos($b, '.')) {            $_arr_b = explode('.', $b);            if (isset($_arr_b[1])) {                $_lb_l = strlen($_arr_b[1]);                $_lb = $_arr_b[1];            }            $_lb_n = $_arr_b[0];        } else {            $_lb_n = $b;            $_lb = '';            $_lb_l = 0;        }        /* 整数相加 */        $_lr_n = self::realAdd($_la_n, $_lb_n);        /* 小数同位 */        if ($_la_l && $_lb_l) {            if ($_la_l > $_lb_l) {                $_lb = str_pad($_lb, $_la_l, '0', STR_PAD_RIGHT);            } elseif ($_lb_l > $_la_l) {                $_la = str_pad($_la, $_lb_l, '0', STR_PAD_RIGHT);            }            $_lr_low = self::realAdd($_la, $_lb);            $_lr_long = strlen($_lr_low);            $_lr_a = strlen($_la);            if ($_lr_long > $_lr_a) {                $_real_low = substr($_lr_low, $_lr_long - $_lr_a);                $_real_low_n = substr($_lr_low, 0, $_lr_long - $_lr_a);                $_real_n = self::realAdd($_lr_n, $_real_low_n);                return $_real_n.'.'.$_real_low;            }            return $_lr_n.'.'.$_lr_low;        } elseif ($_la_l && !$_lb_l) {            return $_lr_n.'.'.$_la;        } elseif ($_lb_l && !$_la_l) {            return $_lr_n.'.'.$_lb;        } elseif (!$_lb_l && !$_la_l) {            return $_lr_n;        }    }    /**     * 两个大数相减 过滤首尾无用0     *     * @param $a     * @param $b     *     * @return string     */    public static function addBigMic($a, $b) {        $_re = self::realBigMic($a, $b);        if (strpos($_re, '-') === 0) {            $_return_str = ltrim(substr($_re, 1), '0');            if (strpos($_re, '.') === 0) {                return '-0'.rtrim($_return_str);            } else {                return '-'.$_return_str;            }        }        $_return_str = ltrim($_re, '0');        if (strpos($_return_str, '.') === 0) {            return '0'.rtrim($_return_str);        } else {            return $_return_str;        }    }    /**     * 两个大数相减 保留首尾无用0     *     * @param $a     * @param $b     *     * @return string     */    public static function realBigMic($a, $b) {        $_la = '';        $_la_l = 0;        if (strpos($a, '.')) {            $_arr_a = explode('.', $a);            if (isset($_arr_a[1])) {                $_la_l = strlen($_arr_a[1]);                $_la = $_arr_a[1];            }            $_la_n = $_arr_a[0];        } else {            $_la_n = $a;            $_la = '';            $_la_l = 0;        }        $_lb = '';        $_lb_l = 0;        if (strpos($b, '.')) {            $_arr_b = explode('.', $b);            if (isset($_arr_b[1])) {                $_lb_l = strlen($_arr_b[1]);                $_lb = $_arr_b[1];            }            $_lb_n = $_arr_b[0];        } else {            $_lb_n = $b;            $_lb = '';            $_lb_l = 0;        }        /* 整数相减 */        $_lr_n = self::realMic($_la_n, $_lb_n);        /* 小数同位 */        if ($_la_l && $_lb_l) {            if ($_la_l > $_lb_l) {                $_lb = str_pad($_lb, $_la_l, '0', STR_PAD_RIGHT);            } elseif ($_lb_l > $_la_l) {                $_la = str_pad($_la, $_lb_l, '0', STR_PAD_RIGHT);            }            $_lr_low = self::realMic($_la, $_lb);            $_lr_long = strlen($_lr_low);            $_lr_a = strlen($_la);            if ($_lr_long > $_lr_a) {                $_real_low = substr($_lr_low, $_lr_long - $_lr_a);                $_real_n = self::realMic($_lr_n, 1);                return $_real_n.'.'.$_real_low;            }            return $_lr_n.'.'.$_lr_low;        } elseif ($_la_l && !$_lb_l) {            return $_lr_n.'.'.$_la;        } elseif ($_lb_l && !$_la_l) {            return $_lr_n.'.'.$_lb;        } elseif (!$_lb_l && !$_la_l) {            return $_lr_n;        }    }    /**     * 两数相加     *     * @param $a     * @param $b     *     * @return string     */    public static function realAdd($a, $b) {        $a_str = $a.'';        $b_str = $b.'';        $m = strlen($a_str);        $n = strlen($b_str);        $num = $m > $n ? $m : $n;        $result = '';        $flag = 0;        while ($num--) {            $t1 = 0;            $t2 = 0;            if ($m > 0) {                $t1 = $a_str[--$m];            }            if ($n > 0) {                $t2 = $b_str[--$n];            }            $t = $t1 + $t2 + $flag;            if ($t > 9) {                $flag = 1;                $t = $t - 10;            } else {                $flag = 0;            }            $result = $t.$result;        }        if ($flag) {            $result = $flag.$result;        }        return $result;    }    /**     * 两数相减     *     * @param $a     * @param $b     *     * @return string     */    public static function realMic($a, $b) {        $a_str = $a.'';        $b_str = $b.'';        $m = strlen($a_str);        $n = strlen($b_str);        if ($m < $n) {            $_need_flag = true;            $a_str = $b.'';            $_rm = $m;            $m = $n;            $n = $_rm;            unset($_rm);            $b_str = $a.'';        } else {            $_need_flag = false;        }        $num = $m > $n ? $m : $n;        $result = '';        $flag = 0;        while ($num--) {            $t1 = 0;            $t2 = 0;            if ($m > 0) {                $t1 = $a_str[--$m];            }            if ($n > 0) {                $t2 = $b_str[--$n];            }            $_mt = $t2 + $flag;            if ($t1 < $_mt) {                $t = $t1 + 10 - $_mt;                $flag = 1;            } else {                $t = $t1 - $_mt;                $flag = 0;            }            $result = $t.$result;        }        if ($flag) {            $result = '-'.$result;        }        if ($_need_flag) {            $result = '-'.$result;        }        return $result;    }    /**     * 获取指定位数的随机数字     *     * @param int  $num        位数     * @param bool $first_zero 是否首位不为零     *     * @return string     */    public static function getRandNum($num = 1, $first_zero = false) {        if (empty($num)) {            return 0;        }        $return_str = '';        for ($i = 0; $i < $num; $i++) {            if ($i == 0 && $first_zero) {                $return_str .= mt_rand(1, 9);            } else {                $return_str .= mt_rand(0, 9);            }        }        return $return_str;    }    /**     * 获取随机手机号码     *     * @return string     */    public static function getRandMobile() {        return '1'.self::getRandNum(10, true);    }    /**     * 获取随机时间     *     * @param int $before 时间上限     * @param int $after  时间下限     *     * @return false|string     */    public static function getRandTime($before = 0, $after = 0) {        if (empty($before) && empty($after)) {            /* 随机0到rand_Max位数的随机数 */            return date('Y-m-d H:i:s', self::getRandNum(mt_rand(0, 20)));        } else {            if ($before - $after > 1) {                return date('Y-m-d H:i:s', $after + intval(mt_rand(0, $before - $after - 1)));            } else {                if ($before > $after) {                    return date('Y-m-d H:i:s', mt_rand($after, $before));                } else {                    return date('Y-m-d H:i:s');                }            }        }    }    /**     * 获取两数最大的小数点位数     *     * @param     $a     * @param     $b     * @param int $n 默认位数     *     * @return int     */    public static function getMaxPoint($a, $b, $n = 2) {        $_n = $n;        if (strpos($a, '.') || strpos($b, '.')) {            $_al = self::getNumPoint($a);            if ($_al > $_n) {                $_n = $_al;            }            $_bl = self::getNumPoint($b);            if ($_bl > $_n) {                $_n = $_bl;            }        }        return $_n;    }    /**     * 获取一个数的小数位数     *     * @param $a     *     * @return int     */    public static function getNumPoint($a) {        if (strpos($a, '.')) {            $_arr_a = explode('.', $a);            if (isset($_arr_a[1])) {                return strlen($_arr_a[1]);            }        }        return 0;    }    /**     * 两数相减     *     * @param     $a     * @param     $b     *     * @param int $decimals 保留位数     *     * @return string     */    public static function addMic($a, $b, $decimals = 2) {        if (!$decimals) {            $decimals = 2;        }        $_n = self::getMaxPoint($a, $b, $decimals);        return number_format((number_format($a, $_n, '.', '') - number_format($b, $_n, '.', '')), $decimals, '.', '');    }    /**     * 两个数精确相乘  小学生算法     *     * @param $strA     * @param $strB     *     * @return mixed|string     */    public static function accMul($strA, $strB) {        $m = 0;        $_al = self::getNumPoint($strA);        $A = $strA;        if ($_al) {            $m = $m + $_al;            $A = str_replace('.', '', $strA);        }        $B = $strB;        $_bl = self::getNumPoint($strB);        if ($_bl) {            $m = $m + $_bl;            $B = str_replace('.', '', $strB);        }        $sResult = "";        //反转字符串        $A = strrev($A);        $B = strrev($B);        $_a_len = strlen($A);        $_b_len = strlen($B);        $_ab_len = $_a_len + $_b_len;        //建立temp变量        $flag = array();        for ($i = 0; $i < ($_ab_len + 1); $i++) {            $flag[$i] = "0";        }        //依次相乘叠加        for ($i = 0; $i < $_a_len; $i++) {            for ($j = 0; $j < $_b_len; $j++) {                $flag[$i + $j] = $flag[$i + $j] + (intval($A[$i]) * intval($B[$j])) % 10;                $flag[$i + $j + 1] = $flag[$i + $j + 1] + (int)((intval($A[$i]) * intval($B[$j])) / 10);            }        }        //再次相乘叠加        for ($i = 0; $i < count($flag) - 1; $i++) {            $flag[$i + 1] = $flag[$i + 1] + (int)(intval($flag[$i]) / 10);            $flag[$i] = intval($flag[$i]) % 10;        }        //去除高位无用的0;        $mark = 0;        for ($i = count($flag) - 1; $i >= 0; $i--) {            if ($flag[$i] != 0 && $mark == 0) {                $mark = $i;            }            if ($mark != 0) {                $sResult = $sResult.$flag[$i];            }        }        if ($sResult == '' && $flag[0] != '') {            $sResult = $flag[0];        }        if ($m) {            $rel = strlen($sResult);            if ($m < $rel) {                return substr($sResult, 0, $rel - $m).'.'.substr($sResult, -$m);            } else {                if ($m == $rel) {                    return '0.'.$sResult;                } else {                    $re = '0.';                    for ($i = 0; $i < $m - $rel; $i++) {                        $re .= '0';                    }                    return $re.$sResult;                }            }        } else {            return $sResult;        }    }    /**     * 高精度除法 php 自带     *     * @param     $a     * @param     $b     * @param int $n     *$a=bcdiv("111111111111111111","1");     *     * @return string     */    public static function divNum($a, $b, $n = 3) {        return bcdiv($a, $b, $n);    }    /**     * 任意精度除法  a/b 保留n 位小数  用php bcdiv方法     *     * @param $a     * @param $b     * @param $n     *     * @return string     */    public static function phpDivNum($a, $b, $n = 0) {        if (!$n) {            $n = self::DIV_N;        }        $_str_a = $a.'';        $_str_b = $b.'';        /* 先计算符号 */        $_a_one = substr($a, 0, 1);        $_b_one = substr($b, 0, 1);        $_need_flag = false;        if ('-' == $_a_one && '-' == $_b_one) {            $_str_a = substr($a, 1);            $_str_b = substr($b, 1);            $b = $_str_b;            $a = $_str_a;        } elseif ('-' == $_a_one && '-' != $_b_one) {            $_str_a = substr($a, 1);            $a = $_str_a;            $_need_flag = true;        } elseif ('-' != $_a_one && '-' == $_b_one) {            $_str_b = substr($b, 1);            $b = $_str_b;            $_need_flag = true;        } elseif ('-' != $_a_one && '-' != $_b_one) {        }        /* 先计算符号 */        /* 对齐小数点同时去掉小数点 start */        $_an = self::getNumPoint($a);        $_bn = self::getNumPoint($b);        if ($_an > $_bn) {            $_point_str_l = strlen($_str_b) + $_an - $_bn;            $_str_b = str_pad($_str_b, $_point_str_l, '0', STR_PAD_RIGHT);            if ($_an > $n) {                $n = $_an + 1;            }        } elseif ($_bn > $_an) {            $_point_str_l = strlen($_str_a) + $_bn - $_an;            $_str_a = str_pad($_str_a, $_point_str_l, '0', STR_PAD_RIGHT);            if ($_bn > $n) {                $n = $_bn + 1;            }        }        $_str_b = str_replace('.', '', $_str_b);        $_str_a = str_replace('.', '', $_str_a);        /* 对齐小数点同时去掉小数点 end */        $_do_a = str_pad($_str_a, strlen($_str_a) + $n, '0', STR_PAD_RIGHT);        $return_str = self::realDivNum($_do_a, $_str_b, $n);        $_re_z = str_pad('0.', 1 + $n, '0', STR_PAD_RIGHT).'1';        if ($_need_flag) {            return '-'.self::accMul($return_str, $_re_z);        } else {            return self::accMul($return_str, $_re_z);        }    }    /**     * 用php函数计算两数相除精确到 n 个位     *     * @param     $a     * @param     $b     * @param int $n     *     * @return string     */    public static function realDivNum($a, $b, $n = 0) {        if (!$n) {            $n = self::DIV_N;        }        return self::divNum($a, $b, $n);    }    /**     * 用自己写的小生除法进行计算两个数相除 保留$n 位小数     *     * @param     $a     * @param     $b     * @param int $n     *     * @return mixed|string     */    public static function bigDivNum($a, $b, $n = 0) {        $_str_a = $a.'';        $_str_b = $b.'';        if (!$n) {            $_n = self::DIV_N;        } else {            $_n = $n + 1;        }        /* 先计算符号 */        $_a_one = substr($a, 0, 1);        $_b_one = substr($b, 0, 1);        $_need_flag = false;        if ('-' == $_a_one && '-' == $_b_one) {            $_str_a = substr($a, 1);            $_str_b = substr($b, 1);            $b = $_str_b;            $a = $_str_a;        } elseif ('-' == $_a_one && '-' != $_b_one) {            $_str_a = substr($a, 1);            $a = $_str_a;            $_need_flag = true;        } elseif ('-' != $_a_one && '-' == $_b_one) {            $_str_b = substr($b, 1);            $b = $_str_b;            $_need_flag = true;        } elseif ('-' != $_a_one && '-' != $_b_one) {        }        /* 先计算符号 */        /* 对齐小数点同时去掉小数点 start */        $_an = self::getNumPoint($a);        $_bn = self::getNumPoint($b);        if ($_an > $_bn) {            $_point_str_l = strlen($_str_b) + $_an - $_bn;            $_str_b = str_pad($_str_b, $_point_str_l, '0', STR_PAD_RIGHT);            if ($_an > $_n) {                $_n = $_an + 1;            }        } elseif ($_bn > $_an) {            $_point_str_l = strlen($_str_a) + $_bn - $_an;            $_str_a = str_pad($_str_a, $_point_str_l, '0', STR_PAD_RIGHT);            if ($_bn > $_n) {                $_n = $_bn + 1;            }        }        $_str_b = str_replace('.', '', $_str_b);        $_str_a = str_replace('.', '', $_str_a);        /* 对齐小数点同时去掉小数点 end */        $_do_a = str_pad($_str_a, strlen($_str_a) + $_n, '0', STR_PAD_RIGHT);        $return_arr = self::getDevFist($_do_a, $_str_b, $_n);        $_re_z = str_pad('0.', 1 + $_n, '0', STR_PAD_RIGHT).'1';        if ($_need_flag) {            return '-'.self::accMul($return_arr['q'], $_re_z);        } else {            return self::accMul($return_arr['q'], $_re_z);        }    }    /**     * 两数相除     * 获得 商和余数     *  remainder 余数  quotient 商     *     * @param     $a     * @param     $b     *     * @param int $n     *     * @return array     */    public static function getDevFist($a, $b, $n = 0) {        $_n = $n + 1;        $_str_la = strlen($a);        $_str_lb = strlen($b);        if (!($_str_la > $_str_lb)) {/* $a的位数大于 $b的位数 商0 余数为a  */            return array(                'q' => '0',                'r' => $a,            );        }        $_mir = $_str_la - $_str_lb;        if ($_mir < 2) {            return self::getDevRealFist($a, $b);        } else {            $_str_a = $a;            $_str_b = $b;            $_r = str_pad('1', $_mir, '0', STR_PAD_RIGHT);            $_new_b = self::accMul($_str_b, $_r);            $_r_r_arr = self::getDevRealFist($_str_a, $_new_b); /* 取得第一位商 */            $_result = self::accMul($_r_r_arr['q'], $_r);            $_result_r = $_r_r_arr['r'];            $_rr_lr = strlen($_result_r);            if (!($_rr_lr > 1)) {/* 没有余数 */                return array(                    'q' => $_result,                    'r' => $_result_r,                );            }            $_mir_r = $_rr_lr - $_str_lb;            while ($_mir_r > 1 && ($_n > 0)) {                $_r = str_pad('1', $_mir_r, '0', STR_PAD_RIGHT);                $_new_b = self::accMul($b, $_r);                $_r_r_arr = self::getDevRealFist($_result_r, $_new_b); /* 取得第一位商 */                $_result = self::addBigNum($_result, self::accMul($_r_r_arr['q'], $_r));                $_result_r = $_r_r_arr['r'];                $_rr_lr = strlen($_result_r);                if (!($_rr_lr > 1)) {/* 没有余数 */                    return array(                        'q' => $_result,                        'r' => $_result_r,                    );                }                $_mir_r = $_rr_lr - $_str_lb;                $_n = $_n - 1;            }            $_return_rr = self::getDevRealFist($_result_r, $b);            $_result = self::addBigNum($_result, $_return_rr['q']);            return array(                'q' => $_result,                'r' => $_return_rr['r'],            );        }    }    /**     * 获取位数差不大于两位的两数相除的商和余数     *     * @param $a 被除数     * @param $b 除数     *     * @return array     *   array(     *  '     * )     */    public static function getDevRealFist($a, $b) {        $_str_la = strlen($a);        $_str_lb = strlen($b);        if ($_str_la < $_str_lb) {/* $a的位数大于 $b的位数 商0 余数为a  */            return array(                'q' => '0',                'r' => $a,            );        }        $_str_a = $a.'';        $_str_b = $b.'';        $_a_one = substr($_str_a, 0, 1);        $_b_one = substr($_str_b, 0, 1);        if ($_str_la == $_str_lb) {            if ($_a_one < $_b_one) {                return array(                    'q' => '0',                    'r' => $a,                );            } elseif ($_a_one == $_b_one) {                $_q_test = self::addBigMic($_str_a, $_str_b);                if ('-' == substr($_q_test, 0, 1)) {                    return array(                        'q' => '0',                        'r' => $a,                    );                } else {                    return array(                        'q' => '1',                        'r' => $_q_test,                    );                }            } elseif ($_a_one > $_b_one) {                $_q_test = floor($_a_one / $_b_one);                if (1 == $_q_test) {                    $_q_r = self::addBigMic($_str_a, $_str_b);                    return array(                        'q' => '1',                        'r' => $_q_r,                    );                } else {                    $_q_r = self::addBigMic($_str_a, self::accMul($_str_b, $_q_test));                    while ('-' == substr($_q_r, 0, 1)) {                        $_q_test = $_q_test - 1;                        $_q_r = self::addBigMic($_str_a, self::accMul($_str_b, $_q_test));                    }                    return array(                        'q' => $_q_test,                        'r' => $_q_r,                    );                }            }        } elseif ($_str_la > $_str_lb) {            $_min_r = $_str_la - $_str_lb;            if (1 == $_min_r) {/* 被除数比除数多一位  */                $_a_two = substr($_str_a, 0, 2);                $_q_test = floor($_a_two / $_b_one);                if (1 == $_q_test) {                    $_q_r = self::addBigMic($_str_a, $_str_b);                    return array(                        'q' => '1',                        'r' => $_q_r,                    );                } else {                    $_q_r = self::addBigMic($_str_a, self::accMul($_str_b, $_q_test));                    while ('-' == substr($_q_r, 0, 1)) {                        $_q_test = $_q_test - 1;                        $_q_r = self::addBigMic($_str_a, self::accMul($_str_b, $_q_test));                    }                    return array(                        'q' => $_q_test,                        'r' => $_q_r,                    );                }            } else {/* 被除数比除数多两位以上 */                return array(                    'q' => 'error',                    'r' => 'a比b多两位或2位以上',                );            }        }    }}
 |