|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Locale |
|
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
19 * @version $Id: PhpMath.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
20 */ |
|
21 |
|
22 |
|
23 /** |
|
24 * Utility class for proxying math function to bcmath functions, if present, |
|
25 * otherwise to PHP builtin math operators, with limited detection of overflow conditions. |
|
26 * Sampling of PHP environments and platforms suggests that at least 80% to 90% support bcmath. |
|
27 * This file should only be loaded for the 10% to 20% lacking access to the bcmath extension. |
|
28 * |
|
29 * @category Zend |
|
30 * @package Zend_Locale |
|
31 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
32 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
33 */ |
|
34 class Zend_Locale_Math_PhpMath extends Zend_Locale_Math |
|
35 { |
|
36 public static function disable() |
|
37 { |
|
38 self::$_bcmathDisabled = true; |
|
39 self::$add = array('Zend_Locale_Math_PhpMath', 'Add'); |
|
40 self::$sub = array('Zend_Locale_Math_PhpMath', 'Sub'); |
|
41 self::$pow = array('Zend_Locale_Math_PhpMath', 'Pow'); |
|
42 self::$mul = array('Zend_Locale_Math_PhpMath', 'Mul'); |
|
43 self::$div = array('Zend_Locale_Math_PhpMath', 'Div'); |
|
44 self::$comp = array('Zend_Locale_Math_PhpMath', 'Comp'); |
|
45 self::$sqrt = array('Zend_Locale_Math_PhpMath', 'Sqrt'); |
|
46 self::$mod = array('Zend_Locale_Math_PhpMath', 'Mod'); |
|
47 self::$scale = array('Zend_Locale_Math_PhpMath', 'Scale'); |
|
48 |
|
49 self::$defaultScale = 0; |
|
50 self::$defaultPrecision = 1; |
|
51 } |
|
52 |
|
53 public static $defaultScale; |
|
54 public static $defaultPrecision; |
|
55 |
|
56 |
|
57 public static function Add($op1, $op2, $scale = null) |
|
58 { |
|
59 if ($scale === null) { |
|
60 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
61 $precision = Zend_Locale_Math_PhpMath::$defaultPrecision; |
|
62 } else { |
|
63 $precision = pow(10, -$scale); |
|
64 } |
|
65 |
|
66 if (empty($op1)) { |
|
67 $op1 = 0; |
|
68 } |
|
69 $op1 = self::normalize($op1); |
|
70 $op2 = self::normalize($op2); |
|
71 $result = $op1 + $op2; |
|
72 if (is_infinite($result) or (abs($result - $op2 - $op1) > $precision)) { |
|
73 require_once 'Zend/Locale/Math/Exception.php'; |
|
74 throw new Zend_Locale_Math_Exception("addition overflow: $op1 + $op2 != $result", $op1, $op2, $result); |
|
75 } |
|
76 |
|
77 return self::round(self::normalize($result), $scale); |
|
78 } |
|
79 |
|
80 public static function Sub($op1, $op2, $scale = null) |
|
81 { |
|
82 if ($scale === null) { |
|
83 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
84 $precision = Zend_Locale_Math_PhpMath::$defaultPrecision; |
|
85 } else { |
|
86 $precision = pow(10, -$scale); |
|
87 } |
|
88 |
|
89 if (empty($op1)) { |
|
90 $op1 = 0; |
|
91 } |
|
92 $op1 = self::normalize($op1); |
|
93 $op2 = self::normalize($op2); |
|
94 $result = $op1 - $op2; |
|
95 if (is_infinite($result) or (abs($result + $op2 - $op1) > $precision)) { |
|
96 require_once 'Zend/Locale/Math/Exception.php'; |
|
97 throw new Zend_Locale_Math_Exception("subtraction overflow: $op1 - $op2 != $result", $op1, $op2, $result); |
|
98 } |
|
99 |
|
100 return self::round(self::normalize($result), $scale); |
|
101 } |
|
102 |
|
103 public static function Pow($op1, $op2, $scale = null) |
|
104 { |
|
105 if ($scale === null) { |
|
106 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
107 } |
|
108 |
|
109 $op1 = self::normalize($op1); |
|
110 $op2 = self::normalize($op2); |
|
111 |
|
112 // BCMath extension doesn't use decimal part of the power |
|
113 // Provide the same behavior |
|
114 $op2 = ($op2 > 0) ? floor($op2) : ceil($op2); |
|
115 |
|
116 $result = pow($op1, $op2); |
|
117 if (is_infinite($result) or is_nan($result)) { |
|
118 require_once 'Zend/Locale/Math/Exception.php'; |
|
119 throw new Zend_Locale_Math_Exception("power overflow: $op1 ^ $op2", $op1, $op2, $result); |
|
120 } |
|
121 |
|
122 return self::round(self::normalize($result), $scale); |
|
123 } |
|
124 |
|
125 public static function Mul($op1, $op2, $scale = null) |
|
126 { |
|
127 if ($scale === null) { |
|
128 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
129 } |
|
130 |
|
131 if (empty($op1)) { |
|
132 $op1 = 0; |
|
133 } |
|
134 $op1 = self::normalize($op1); |
|
135 $op2 = self::normalize($op2); |
|
136 $result = $op1 * $op2; |
|
137 if (is_infinite($result) or is_nan($result)) { |
|
138 require_once 'Zend/Locale/Math/Exception.php'; |
|
139 throw new Zend_Locale_Math_Exception("multiplication overflow: $op1 * $op2 != $result", $op1, $op2, $result); |
|
140 } |
|
141 |
|
142 return self::round(self::normalize($result), $scale); |
|
143 } |
|
144 |
|
145 public static function Div($op1, $op2, $scale = null) |
|
146 { |
|
147 if ($scale === null) { |
|
148 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
149 } |
|
150 |
|
151 if (empty($op2)) { |
|
152 require_once 'Zend/Locale/Math/Exception.php'; |
|
153 throw new Zend_Locale_Math_Exception("can not divide by zero", $op1, $op2, null); |
|
154 } |
|
155 if (empty($op1)) { |
|
156 $op1 = 0; |
|
157 } |
|
158 $op1 = self::normalize($op1); |
|
159 $op2 = self::normalize($op2); |
|
160 $result = $op1 / $op2; |
|
161 if (is_infinite($result) or is_nan($result)) { |
|
162 require_once 'Zend/Locale/Math/Exception.php'; |
|
163 throw new Zend_Locale_Math_Exception("division overflow: $op1 / $op2 != $result", $op1, $op2, $result); |
|
164 } |
|
165 |
|
166 return self::round(self::normalize($result), $scale); |
|
167 } |
|
168 |
|
169 public static function Sqrt($op1, $scale = null) |
|
170 { |
|
171 if ($scale === null) { |
|
172 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
173 } |
|
174 |
|
175 if (empty($op1)) { |
|
176 $op1 = 0; |
|
177 } |
|
178 $op1 = self::normalize($op1); |
|
179 $result = sqrt($op1); |
|
180 if (is_nan($result)) { |
|
181 return NULL; |
|
182 } |
|
183 |
|
184 return self::round(self::normalize($result), $scale); |
|
185 } |
|
186 |
|
187 public static function Mod($op1, $op2) |
|
188 { |
|
189 if (empty($op1)) { |
|
190 $op1 = 0; |
|
191 } |
|
192 if (empty($op2)) { |
|
193 return NULL; |
|
194 } |
|
195 $op1 = self::normalize($op1); |
|
196 $op2 = self::normalize($op2); |
|
197 if ((int)$op2 == 0) { |
|
198 return NULL; |
|
199 } |
|
200 $result = $op1 % $op2; |
|
201 if (is_nan($result) or (($op1 - $result) % $op2 != 0)) { |
|
202 require_once 'Zend/Locale/Math/Exception.php'; |
|
203 throw new Zend_Locale_Math_Exception("modulus calculation error: $op1 % $op2 != $result", $op1, $op2, $result); |
|
204 } |
|
205 |
|
206 return self::normalize($result); |
|
207 } |
|
208 |
|
209 public static function Comp($op1, $op2, $scale = null) |
|
210 { |
|
211 if ($scale === null) { |
|
212 $scale = Zend_Locale_Math_PhpMath::$defaultScale; |
|
213 } |
|
214 |
|
215 if (empty($op1)) { |
|
216 $op1 = 0; |
|
217 } |
|
218 $op1 = self::normalize($op1); |
|
219 $op2 = self::normalize($op2); |
|
220 if ($scale <> 0) { |
|
221 $op1 = self::round($op1, $scale); |
|
222 $op2 = self::round($op2, $scale); |
|
223 } else { |
|
224 $op1 = ($op1 > 0) ? floor($op1) : ceil($op1); |
|
225 $op2 = ($op2 > 0) ? floor($op2) : ceil($op2); |
|
226 } |
|
227 if ($op1 > $op2) { |
|
228 return 1; |
|
229 } else if ($op1 < $op2) { |
|
230 return -1; |
|
231 } |
|
232 return 0; |
|
233 } |
|
234 |
|
235 public static function Scale($scale) |
|
236 { |
|
237 if ($scale > 9) { |
|
238 require_once 'Zend/Locale/Math/Exception.php'; |
|
239 throw new Zend_Locale_Math_Exception("can not scale to precision $scale", $scale, null, null); |
|
240 } |
|
241 self::$defaultScale = $scale; |
|
242 self::$defaultPrecision = pow(10, -$scale); |
|
243 return true; |
|
244 } |
|
245 } |
|
246 |
|
247 Zend_Locale_Math_PhpMath::disable(); // disable use of bcmath functions |