File indexing completed on 2024-12-22 05:36:49

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Locale
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 
0023 /**
0024  * Utility class for proxying math function to bcmath functions, if present,
0025  * otherwise to PHP builtin math operators, with limited detection of overflow conditions.
0026  * Sampling of PHP environments and platforms suggests that at least 80% to 90% support bcmath.
0027  * This file should only be loaded for the 10% to 20% lacking access to the bcmath extension.
0028  *
0029  * @category   Zend
0030  * @package    Zend_Locale
0031  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0032  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0033  */
0034 class Zend_Locale_Math_PhpMath extends Zend_Locale_Math
0035 {
0036     public static function disable()
0037     {
0038         self::$_bcmathDisabled = true;
0039         self::$add   = array('Zend_Locale_Math_PhpMath', 'Add');
0040         self::$sub   = array('Zend_Locale_Math_PhpMath', 'Sub');
0041         self::$pow   = array('Zend_Locale_Math_PhpMath', 'Pow');
0042         self::$mul   = array('Zend_Locale_Math_PhpMath', 'Mul');
0043         self::$div   = array('Zend_Locale_Math_PhpMath', 'Div');
0044         self::$comp  = array('Zend_Locale_Math_PhpMath', 'Comp');
0045         self::$sqrt  = array('Zend_Locale_Math_PhpMath', 'Sqrt');
0046         self::$mod   = array('Zend_Locale_Math_PhpMath', 'Mod');
0047         self::$scale = array('Zend_Locale_Math_PhpMath', 'Scale');
0048 
0049         self::$defaultScale     = 0;
0050         self::$defaultPrecision = 1;
0051     }
0052 
0053     public static $defaultScale;
0054     public static $defaultPrecision;
0055 
0056 
0057     public static function Add($op1, $op2, $scale = null)
0058     {
0059         if ($scale === null) {
0060             $scale     = Zend_Locale_Math_PhpMath::$defaultScale;
0061             $precision = Zend_Locale_Math_PhpMath::$defaultPrecision;
0062         } else {
0063             $precision = pow(10, -$scale);
0064         }
0065 
0066         if (empty($op1)) {
0067             $op1 = 0;
0068         }
0069         $op1 = self::normalize($op1);
0070         $op2 = self::normalize($op2);
0071         $result = $op1 + $op2;
0072         if (is_infinite($result)  or  (abs($result - $op2 - $op1) > $precision)) {
0073             // require_once 'Zend/Locale/Math/Exception.php';
0074             throw new Zend_Locale_Math_Exception("addition overflow: $op1 + $op2 != $result", $op1, $op2, $result);
0075         }
0076 
0077         return self::round(self::normalize($result), $scale);
0078     }
0079 
0080     public static function Sub($op1, $op2, $scale = null)
0081     {
0082         if ($scale === null) {
0083             $scale     = Zend_Locale_Math_PhpMath::$defaultScale;
0084             $precision = Zend_Locale_Math_PhpMath::$defaultPrecision;
0085         } else {
0086             $precision = pow(10, -$scale);
0087         }
0088 
0089         if (empty($op1)) {
0090             $op1 = 0;
0091         }
0092         $op1  = self::normalize($op1);
0093         $op2  = self::normalize($op2);
0094         $result = $op1 - $op2;
0095         if (is_infinite($result)  or  (abs($result + $op2 - $op1) > $precision)) {
0096             // require_once 'Zend/Locale/Math/Exception.php';
0097             throw new Zend_Locale_Math_Exception("subtraction overflow: $op1 - $op2 != $result", $op1, $op2, $result);
0098         }
0099 
0100         return self::round(self::normalize($result), $scale);
0101     }
0102 
0103     public static function Pow($op1, $op2, $scale = null)
0104     {
0105         if ($scale === null) {
0106             $scale = Zend_Locale_Math_PhpMath::$defaultScale;
0107         }
0108 
0109         $op1 = self::normalize($op1);
0110         $op2 = self::normalize($op2);
0111 
0112         // BCMath extension doesn't use decimal part of the power
0113         // Provide the same behavior
0114         $op2 = ($op2 > 0) ? floor($op2) : ceil($op2);
0115 
0116         $result = pow($op1, $op2);
0117         if (is_infinite($result)  or  is_nan($result)) {
0118             // require_once 'Zend/Locale/Math/Exception.php';
0119             throw new Zend_Locale_Math_Exception("power overflow: $op1 ^ $op2", $op1, $op2, $result);
0120         }
0121 
0122         return self::round(self::normalize($result), $scale);
0123     }
0124 
0125     public static function Mul($op1, $op2, $scale = null)
0126     {
0127         if ($scale === null) {
0128             $scale = Zend_Locale_Math_PhpMath::$defaultScale;
0129         }
0130 
0131         if (empty($op1)) {
0132             $op1 = 0;
0133         }
0134         $op1 = self::normalize($op1);
0135         $op2 = self::normalize($op2);
0136         $result = $op1 * $op2;
0137         if (is_infinite($result)  or  is_nan($result)) {
0138             // require_once 'Zend/Locale/Math/Exception.php';
0139             throw new Zend_Locale_Math_Exception("multiplication overflow: $op1 * $op2 != $result", $op1, $op2, $result);
0140         }
0141 
0142         return self::round(self::normalize($result), $scale);
0143     }
0144 
0145     public static function Div($op1, $op2, $scale = null)
0146     {
0147         if ($scale === null) {
0148             $scale = Zend_Locale_Math_PhpMath::$defaultScale;
0149         }
0150 
0151         if (empty($op2)) {
0152             // require_once 'Zend/Locale/Math/Exception.php';
0153             throw new Zend_Locale_Math_Exception("can not divide by zero", $op1, $op2, null);
0154         }
0155         if (empty($op1)) {
0156             $op1 = 0;
0157         }
0158         $op1 = self::normalize($op1);
0159         $op2 = self::normalize($op2);
0160         $result = $op1 / $op2;
0161         if (is_infinite($result)  or  is_nan($result)) {
0162             // require_once 'Zend/Locale/Math/Exception.php';
0163             throw new Zend_Locale_Math_Exception("division overflow: $op1 / $op2 != $result", $op1, $op2, $result);
0164         }
0165 
0166         return self::round(self::normalize($result), $scale);
0167     }
0168 
0169     public static function Sqrt($op1, $scale = null)
0170     {
0171         if ($scale === null) {
0172             $scale = Zend_Locale_Math_PhpMath::$defaultScale;
0173         }
0174 
0175         if (empty($op1)) {
0176             $op1 = 0;
0177         }
0178         $op1 = self::normalize($op1);
0179         $result = sqrt($op1);
0180         if (is_nan($result)) {
0181             return NULL;
0182         }
0183 
0184         return self::round(self::normalize($result), $scale);
0185     }
0186 
0187     public static function Mod($op1, $op2)
0188     {
0189         if (empty($op1)) {
0190             $op1 = 0;
0191         }
0192         if (empty($op2)) {
0193             return NULL;
0194         }
0195         $op1 = self::normalize($op1);
0196         $op2 = self::normalize($op2);
0197         if ((int)$op2 == 0) {
0198             return NULL;
0199         }
0200         $result = $op1 % $op2;
0201         if (is_nan($result)  or  (($op1 - $result) % $op2 != 0)) {
0202             // require_once 'Zend/Locale/Math/Exception.php';
0203             throw new Zend_Locale_Math_Exception("modulus calculation error: $op1 % $op2 != $result", $op1, $op2, $result);
0204         }
0205 
0206         return self::normalize($result);
0207     }
0208 
0209     public static function Comp($op1, $op2, $scale = null)
0210     {
0211         if ($scale === null) {
0212             $scale     = Zend_Locale_Math_PhpMath::$defaultScale;
0213         }
0214 
0215         if (empty($op1)) {
0216             $op1 = 0;
0217         }
0218         $op1 = self::normalize($op1);
0219         $op2 = self::normalize($op2);
0220         if ($scale <> 0) {
0221             $op1 = self::round($op1, $scale);
0222             $op2 = self::round($op2, $scale);
0223         } else {
0224             $op1 = ($op1 > 0) ? floor($op1) : ceil($op1);
0225             $op2 = ($op2 > 0) ? floor($op2) : ceil($op2);
0226         }
0227         if ($op1 > $op2) {
0228             return 1;
0229         } else if ($op1 < $op2) {
0230             return -1;
0231         }
0232         return 0;
0233     }
0234 
0235     public static function Scale($scale)
0236     {
0237         if ($scale > 9) {
0238             // require_once 'Zend/Locale/Math/Exception.php';
0239             throw new Zend_Locale_Math_Exception("can not scale to precision $scale", $scale, null, null);
0240         }
0241         self::$defaultScale     = $scale;
0242         self::$defaultPrecision = pow(10, -$scale);
0243         return true;
0244     }
0245 }
0246 
0247 Zend_Locale_Math_PhpMath::disable(); // disable use of bcmath functions