ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilMath.php
Go to the documentation of this file.
1 <?php
2 /*
3  +-----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +-----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2006 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +-----------------------------------------------------------------------------+
22 */
23 
32 class ilMath
33 {
34  /*
35  * Add two numbers
36  */
37  public static function _add($left_operand, $right_operand, $scale = 50)
38  {
39  $left_operand=ilMath::bcconv($left_operand);
40  $right_operand=ilMath::bcconv($right_operand);
41  $scale=ilMath::bcconv($scale);
42 
43  if (function_exists("bcadd"))
44  {
45  return bcadd($left_operand, $right_operand, $scale);
46  }
47  else
48  {
49  $res = $left_operand + $right_operand;
50  if (is_numeric($scale)) $res = round($res, $scale);
51  return $res;
52  }
53  }
54 
55  /*
56  * Compare two numbers
57  */
58  public static function _comp($left_operand, $right_operand, $scale = 50)
59  {
60  $left_operand=ilMath::bcconv($left_operand);
61  $right_operand=ilMath::bcconv($right_operand);
62  $scale=ilMath::bcconv($scale);
63 
64  if (function_exists("bccomp"))
65  {
66  return bccomp($left_operand, $right_operand, $scale);
67  }
68  else
69  {
70  if (is_numeric($scale))
71  {
72  $left_operand = round($left_operand, $scale);
73  $right_operand = round($right_operand, $scale);
74  }
75  if ($left_operand == $right_operand) return 0;
76  if ($left_operand > $right_operand) return 1;
77  return -1;
78  }
79  }
80 
81  /*
82  * Divide two numbers
83  */
84  public static function _div($left_operand, $right_operand, $scale = 50)
85  {
86  $left_operand=ilMath::bcconv($left_operand);
87  $right_operand=ilMath::bcconv($right_operand);
88  $scale=ilMath::bcconv($scale);
89 
90  if (function_exists("bcdiv"))
91  {
92  return bcdiv($left_operand, $right_operand, $scale);
93  }
94  else
95  {
96  if ($right_operand == 0) return NULL;
97  $res = $left_operand / $right_operand;
98  if (is_numeric($scale)) $res = round($res, $scale);
99  return $res;
100  }
101  }
102 
103  /*
104  * Get modulus of two numbers
105  */
106  public static function _mod($left_operand, $modulus)
107  {
108  $left_operand=ilMath::bcconv($left_operand);
109  $modulus=ilMath::bcconv($modulus);
110 
111  if (function_exists("bcmod"))
112  {
113  return bcmod($left_operand, $modulus);
114  }
115  else
116  {
117  return $left_operand % $modulus;
118  }
119  }
120 
121  /*
122  * Multiplicate two numbers
123  */
124  public static function _mul($left_operand, $right_operand, $scale = 50)
125  {
126  $left_operand=ilMath::bcconv($left_operand);
127  $right_operand=ilMath::bcconv($right_operand);
128  $scale=ilMath::bcconv($scale);
129 
130  if (function_exists("bcmul"))
131  {
132  return bcmul($left_operand, $right_operand, $scale);
133  }
134  else
135  {
136  $res = $left_operand * $right_operand;
137  if (is_numeric($scale)) $res = round($res, $scale);
138  return $res;
139  }
140  }
141 
142  /*
143  * Raise a number to another
144  */
145  public static function _pow($left_operand, $right_operand, $scale = 50)
146  {
147  $left_operand=ilMath::bcconv($left_operand);
148  $right_operand=ilMath::bcconv($right_operand);
149  $scale=ilMath::bcconv($scale);
150 
151  if(function_exists("bcpow"))
152  {
153  // bcpow() only supports exponents less than or equal to 2^31-1.
154  // Also, bcpow() does not support decimal numbers.
155  // If you have scale set to 0, then the exponent is converted to an integer; otherwise an error is generated.
156  $left_operand_dec = ilMath::exp2dec($left_operand);
157  $right_operand_dec = ilMath::exp2dec($right_operand);
158 
159  $is_exponent_decimal_number = strpos($right_operand_dec, '.') !== false;
160 
161  // bcpow does NOT support decimal exponents
162  if(!$is_exponent_decimal_number)
163  {
164  return bcpow($left_operand_dec, $right_operand_dec, $scale);
165  }
166  }
167 
168  $res = pow($left_operand, $right_operand);
169  if (is_numeric($scale)) $res = round($res, $scale);
170  return $res;
171  }
172 
173  /*
174  * Get the square root of a number
175  */
176  public static function _sqrt($operand, $scale = 50)
177  {
178  $operand=ilMath::bcconv($operand);
179  $scale=ilMath::bcconv($scale);
180 
181  if (function_exists("bcsqrt"))
182  {
183  return bcsqrt($operand, $scale);
184  }
185  else
186  {
187  $res = sqrt($operand);
188  if (is_numeric($scale)) $res = round($res, $scale);
189  return $res;
190  }
191  }
192 
193  /*
194  * Subtract two numbers
195  */
196  public static function _sub($left_operand, $right_operand, $scale = 50)
197  {
198  $left_operand=ilMath::bcconv($left_operand);
199  $right_operand=ilMath::bcconv($right_operand);
200  $scale=ilMath::bcconv($scale);
201 
202  if (function_exists("bcsub"))
203  {
204  return bcsub($left_operand, $right_operand, $scale);
205  }
206  else
207  {
208  $res = $left_operand - $right_operand;
209  if (is_numeric($scale)) $res = round($res, $scale);
210  return $res;
211  }
212  }
213 
214  /*
215  * Converts numbers in the form "1.5e4" into decimal notation
216  * Only available for bcmath
217  */
218  function exp2dec($float_str)
219  {
220  // make sure its a standard php float string (i.e. change 0.2e+2 to 20)
221  // php will automatically format floats decimally if they are within a certain range
222  $original = $float_str; // store original float, so we can return a float keeping the pecision when possible
223  $float_str = (string)((float)($float_str));
224  $float_str = str_replace(",", ".", $float_str); // convert ',' to '.' (float casting was locale sensitive)
225 
226  // if there is an E in the float string
227  if(($pos = strpos(strtolower($float_str), 'e')) !== false)
228  {
229  // get either side of the E, e.g. 1.6E+6 => exp E+6, num 1.6
230  $exp = substr($float_str, $pos+1);
231  $num = substr($float_str, 0, $pos);
232 
233  // strip off num sign, if there is one, and leave it off if its + (not required)
234  if((($num_sign = $num[0]) === '+') || ($num_sign === '-')) $num = substr($num, 1);
235  else $num_sign = '';
236  if($num_sign === '+') $num_sign = '';
237 
238  // strip off exponential sign ('+' or '-' as in 'E+6') if there is one, otherwise throw error, e.g. E+6 => '+'
239  if((($exp_sign = $exp[0]) === '+') || ($exp_sign === '-')) $exp = substr($exp, 1);
240  else trigger_error("Could not convert exponential notation to decimal notation: invalid float string '$float_str'", E_USER_ERROR);
241 
242  // get the number of decimal places to the right of the decimal point (or 0 if there is no dec point), e.g., 1.6 => 1
243  $right_dec_places = (($dec_pos = strpos($num, '.')) === false) ? 0 : strlen(substr($num, $dec_pos+1));
244  // get the number of decimal places to the left of the decimal point (or the length of the entire num if there is no dec point), e.g. 1.6 => 1
245  $left_dec_places = ($dec_pos === false) ? strlen($num) : strlen(substr($num, 0, $dec_pos));
246 
247  // work out number of zeros from exp, exp sign and dec places, e.g. exp 6, exp sign +, dec places 1 => num zeros 5
248  if($exp_sign === '+') $num_zeros = $exp - $right_dec_places;
249  else $num_zeros = $exp - $left_dec_places;
250 
251  // build a string with $num_zeros zeros, e.g. '0' 5 times => '00000'
252  $zeros = str_pad('', $num_zeros, '0');
253 
254  // strip decimal from num, e.g. 1.6 => 16
255  if($dec_pos !== false) $num = str_replace('.', '', $num);
256 
257  // if positive exponent, return like 1600000
258  if($exp_sign === '+') return $num_sign.$num.$zeros;
259  // if negative exponent, return like 0.0000016
260  else return $num_sign.'0.'.$zeros.$num;
261  }
262  // otherwise, assume already in decimal notation and return
263  else return $original;
264  }
265 
266  public static function isCoprimeFraction($numerator, $denominator)
267  {
268  $gcd = self::getGreatestCommonDivisor(abs($numerator), abs($denominator));
269 
270  return $gcd == 1 ? true : false;
271  }
272 
273  public static function getGreatestCommonDivisor($a, $b)
274  {
275  if ($b > 0)
276  {
277  return self::getGreatestCommonDivisor($b, $a % $b);
278  }
279  else
280  {
281  return $a;
282  }
283  }
284 
285  public static function _round($value, $precision = 0)
286  {
287  return number_format($value, $precision, '.', '');
288  }
289 
290  public static function _equals($value1, $value2, $scale)
291  {
292  return self::_comp($value1, $value2, $scale) === 0;
293  }
294 
301  private static function bcconv($fNumber)
302  {
303  $fNumber=ilMath::exp2dec($fNumber);
304  $locale_info = localeconv();
305  if($locale_info["decimal_point"] != ".")
306  {
307  $sAppend = '';
308  $iDecimals = ini_get('precision') - floor(log10(abs($fNumber)));
309  if (0 > $iDecimals)
310  {
311  $fNumber *= pow(10, $iDecimals);
312  $sAppend = str_repeat('0', -$iDecimals);
313  $iDecimals = 0;
314  }
315  return number_format($fNumber, $iDecimals, '.', '').$sAppend;
316  }
317  return $fNumber;
318  }
319 }
320 ?>