<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * @category Zend * @package Zend_Locale * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id$ */ /** * Utility class for proxying math function to bcmath functions, if present, * otherwise to PHP builtin math operators, with limited detection of overflow conditions. * Sampling of PHP environments and platforms suggests that at least 80% to 90% support bcmath. * This file should only be loaded for the 10% to 20% lacking access to the bcmath extension. * * @category Zend * @package Zend_Locale * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Locale_Math_PhpMath extends Zend_Locale_Math { public static function disable() { self::$_bcmathDisabled = true; self::$add = array('Zend_Locale_Math_PhpMath', 'Add'); self::$sub = array('Zend_Locale_Math_PhpMath', 'Sub'); self::$pow = array('Zend_Locale_Math_PhpMath', 'Pow'); self::$mul = array('Zend_Locale_Math_PhpMath', 'Mul'); self::$div = array('Zend_Locale_Math_PhpMath', 'Div'); self::$comp = array('Zend_Locale_Math_PhpMath', 'Comp'); self::$sqrt = array('Zend_Locale_Math_PhpMath', 'Sqrt'); self::$mod = array('Zend_Locale_Math_PhpMath', 'Mod'); self::$scale = array('Zend_Locale_Math_PhpMath', 'Scale'); self::$defaultScale = 0; self::$defaultPrecision = 1; } public static $defaultScale; public static $defaultPrecision; public static function Add($op1, $op2, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; $precision = Zend_Locale_Math_PhpMath::$defaultPrecision; } else { $precision = pow(10, -$scale); } if (empty($op1)) { $op1 = 0; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); $result = $op1 + $op2; if (is_infinite($result) or (abs($result - $op2 - $op1) > $precision)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("addition overflow: $op1 + $op2 != $result", $op1, $op2, $result); } return self::round(self::normalize($result), $scale); } public static function Sub($op1, $op2, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; $precision = Zend_Locale_Math_PhpMath::$defaultPrecision; } else { $precision = pow(10, -$scale); } if (empty($op1)) { $op1 = 0; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); $result = $op1 - $op2; if (is_infinite($result) or (abs($result + $op2 - $op1) > $precision)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("subtraction overflow: $op1 - $op2 != $result", $op1, $op2, $result); } return self::round(self::normalize($result), $scale); } public static function Pow($op1, $op2, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); // BCMath extension doesn't use decimal part of the power // Provide the same behavior $op2 = ($op2 > 0) ? floor($op2) : ceil($op2); $result = pow($op1, $op2); if (is_infinite($result) or is_nan($result)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("power overflow: $op1 ^ $op2", $op1, $op2, $result); } return self::round(self::normalize($result), $scale); } public static function Mul($op1, $op2, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; } if (empty($op1)) { $op1 = 0; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); $result = $op1 * $op2; if (is_infinite($result) or is_nan($result)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("multiplication overflow: $op1 * $op2 != $result", $op1, $op2, $result); } return self::round(self::normalize($result), $scale); } public static function Div($op1, $op2, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; } if (empty($op2)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("can not divide by zero", $op1, $op2, null); } if (empty($op1)) { $op1 = 0; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); $result = $op1 / $op2; if (is_infinite($result) or is_nan($result)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("division overflow: $op1 / $op2 != $result", $op1, $op2, $result); } return self::round(self::normalize($result), $scale); } public static function Sqrt($op1, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; } if (empty($op1)) { $op1 = 0; } $op1 = self::normalize($op1); $result = sqrt($op1); if (is_nan($result)) { return NULL; } return self::round(self::normalize($result), $scale); } public static function Mod($op1, $op2) { if (empty($op1)) { $op1 = 0; } if (empty($op2)) { return NULL; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); if ((int)$op2 == 0) { return NULL; } $result = $op1 % $op2; if (is_nan($result) or (($op1 - $result) % $op2 != 0)) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("modulus calculation error: $op1 % $op2 != $result", $op1, $op2, $result); } return self::normalize($result); } public static function Comp($op1, $op2, $scale = null) { if ($scale === null) { $scale = Zend_Locale_Math_PhpMath::$defaultScale; } if (empty($op1)) { $op1 = 0; } $op1 = self::normalize($op1); $op2 = self::normalize($op2); if ($scale <> 0) { $op1 = self::round($op1, $scale); $op2 = self::round($op2, $scale); } else { $op1 = ($op1 > 0) ? floor($op1) : ceil($op1); $op2 = ($op2 > 0) ? floor($op2) : ceil($op2); } if ($op1 > $op2) { return 1; } else if ($op1 < $op2) { return -1; } return 0; } public static function Scale($scale) { if ($scale > 9) { require_once 'Zend/Locale/Math/Exception.php'; throw new Zend_Locale_Math_Exception("can not scale to precision $scale", $scale, null, null); } self::$defaultScale = $scale; self::$defaultPrecision = pow(10, -$scale); return true; } } Zend_Locale_Math_PhpMath::disable(); // disable use of bcmath functions