ILIAS  release_4-3 Revision
 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  if (function_exists("bcadd"))
40  {
41  return bcadd(ilMath::exp2dec($left_operand), ilMath::exp2dec($right_operand), $scale);
42  }
43  else
44  {
45  $res = $left_operand + $right_operand;
46  if (is_numeric($scale)) $res = round($res, $scale);
47  return $res;
48  }
49  }
50 
51  /*
52  * Compare two numbers
53  */
54  public static function _comp($left_operand, $right_operand, $scale = 50)
55  {
56  if (function_exists("bccomp"))
57  {
58  return bccomp(ilMath::exp2dec($left_operand), ilMath::exp2dec($right_operand), $scale);
59  }
60  else
61  {
62  if (is_numeric($scale))
63  {
64  $left_operand = round($left_operand, $scale);
65  $right_operand = round($right_operand, $scale);
66  }
67  if ($left_operand == $right_operand) return 0;
68  if ($left_operand > $right_operand) return 1;
69  return -1;
70  }
71  }
72 
73  /*
74  * Divide two numbers
75  */
76  public static function _div($left_operand, $right_operand, $scale = 50)
77  {
78  if (function_exists("bcdiv"))
79  {
80  return bcdiv(ilMath::exp2dec($left_operand), ilMath::exp2dec($right_operand), $scale);
81  }
82  else
83  {
84  if ($right_operand == 0) return NULL;
85  $res = $left_operand / $right_operand;
86  if (is_numeric($scale)) $res = round($res, $scale);
87  return $res;
88  }
89  }
90 
91  /*
92  * Get modulus of two numbers
93  */
94  public static function _mod($left_operand, $modulus)
95  {
96  if (function_exists("bcmod"))
97  {
98  return bcmod(ilMath::exp2dec($left_operand), $modulus);
99  }
100  else
101  {
102  return $left_operand % $right_operand;
103  }
104  }
105 
106  /*
107  * Multiplicate two numbers
108  */
109  public static function _mul($left_operand, $right_operand, $scale = 50)
110  {
111  if (function_exists("bcmul"))
112  {
113  return bcmul(ilMath::exp2dec($left_operand), ilMath::exp2dec($right_operand), $scale);
114  }
115  else
116  {
117  $res = $left_operand * $right_operand;
118  if (is_numeric($scale)) $res = round($res, $scale);
119  return $res;
120  }
121  }
122 
123  /*
124  * Raise a number to another
125  */
126  public static function _pow($left_operand, $right_operand, $scale = 50)
127  {
128  if(function_exists("bcpow"))
129  {
130  // bcpow() only supports exponents less than or equal to 2^31-1.
131  // Also, bcpow() does not support decimal numbers.
132  // If you have scale set to 0, then the exponent is converted to an integer; otherwise an error is generated.
133  $left_operand_dec = ilMath::exp2dec($left_operand);
134  $right_operand_dec = ilMath::exp2dec($right_operand);
135 
136  $is_exponent_decimal_number = strpos($right_operand_dec, '.') !== false;
137  if(!$is_exponent_decimal_number || $scale > 14)
138  {
139  return bcpow($left_operand_dec, $right_operand_dec, $scale);
140  }
141 
142  // fall through
143  }
144 
145  $res = pow($left_operand, $right_operand);
146  if (is_numeric($scale)) $res = round($res, $scale);
147  return $res;
148  }
149 
150  /*
151  * Get the square root of a number
152  */
153  public static function _sqrt($operand, $scale = 50)
154  {
155  if (function_exists("bcsqrt"))
156  {
157  return bcsqrt(ilMath::exp2dec($operand), $scale);
158  }
159  else
160  {
161  $res = sqrt($operand);
162  if (is_numeric($scale)) $res = round($res, $scale);
163  return $res;
164  }
165  }
166 
167  /*
168  * Subtract two numbers
169  */
170  public static function _sub($left_operand, $right_operand, $scale = 50)
171  {
172  if (function_exists("bcsub"))
173  {
174  return bcsub(ilMath::exp2dec($left_operand), ilMath::exp2dec($right_operand), $scale);
175  }
176  else
177  {
178  $res = $left_operand - $right_operand;
179  if (is_numeric($scale)) $res = round($res, $scale);
180  return $res;
181  }
182  }
183 
184  /*
185  * Converts numbers in the form "1.5e4" into decimal notation
186  * Only available for bcmath
187  */
188  function exp2dec($float_str)
189  {
190  // make sure its a standard php float string (i.e. change 0.2e+2 to 20)
191  // php will automatically format floats decimally if they are within a certain range
192  $original = $float_str; // store original float, so we can return a float keeping the pecision when possible
193  $float_str = (string)((float)($float_str));
194  $float_str = str_replace(",", ".", $float_str); // convert ',' to '.' (float casting was locale sensitive)
195 
196  // if there is an E in the float string
197  if(($pos = strpos(strtolower($float_str), 'e')) !== false)
198  {
199  // get either side of the E, e.g. 1.6E+6 => exp E+6, num 1.6
200  $exp = substr($float_str, $pos+1);
201  $num = substr($float_str, 0, $pos);
202 
203  // strip off num sign, if there is one, and leave it off if its + (not required)
204  if((($num_sign = $num[0]) === '+') || ($num_sign === '-')) $num = substr($num, 1);
205  else $num_sign = '';
206  if($num_sign === '+') $num_sign = '';
207 
208  // strip off exponential sign ('+' or '-' as in 'E+6') if there is one, otherwise throw error, e.g. E+6 => '+'
209  if((($exp_sign = $exp[0]) === '+') || ($exp_sign === '-')) $exp = substr($exp, 1);
210  else trigger_error("Could not convert exponential notation to decimal notation: invalid float string '$float_str'", E_USER_ERROR);
211 
212  // 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
213  $right_dec_places = (($dec_pos = strpos($num, '.')) === false) ? 0 : strlen(substr($num, $dec_pos+1));
214  // 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
215  $left_dec_places = ($dec_pos === false) ? strlen($num) : strlen(substr($num, 0, $dec_pos));
216 
217  // work out number of zeros from exp, exp sign and dec places, e.g. exp 6, exp sign +, dec places 1 => num zeros 5
218  if($exp_sign === '+') $num_zeros = $exp - $right_dec_places;
219  else $num_zeros = $exp - $left_dec_places;
220 
221  // build a string with $num_zeros zeros, e.g. '0' 5 times => '00000'
222  $zeros = str_pad('', $num_zeros, '0');
223 
224  // strip decimal from num, e.g. 1.6 => 16
225  if($dec_pos !== false) $num = str_replace('.', '', $num);
226 
227  // if positive exponent, return like 1600000
228  if($exp_sign === '+') return $num_sign.$num.$zeros;
229  // if negative exponent, return like 0.0000016
230  else return $num_sign.'0.'.$zeros.$num;
231  }
232  // otherwise, assume already in decimal notation and return
233  else return $original;
234  }
235 
236  public static function isCoprimeFraction($numerator, $denominator)
237  {
238  $gcd = self::getGreatestCommonDivisor(abs($numerator), abs($denominator));
239 
240  return $gcd == 1 ? true : false;
241  }
242 
243  public static function getGreatestCommonDivisor($a, $b)
244  {
245  if ($b > 0)
246  {
247  return self::getGreatestCommonDivisor($b, $a % $b);
248  }
249  else
250  {
251  return $a;
252  }
253  }
254 }
255 ?>