1<?php 2/* Copyright (c) 1998-2017 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4require_once 'Services/Math/interfaces/interface.ilMathAdapter.php'; 5 6/** 7 * Class ilMathBaseAdapter 8 * @author Michael Jansen <mjansen@databay.de> 9 */ 10abstract class ilMathBaseAdapter implements ilMathAdapter 11{ 12 /** 13 * This method adapts the behaviour of bcscale() 14 * @param mixed $number 15 * @param integer $scale 16 * @return mixed 17 */ 18 public function applyScale($number, $scale = null) 19 { 20 if (is_numeric($number)) { 21 $scale = (int) $scale; 22 23 $number = $this->exp2dec($number); 24 if (strpos($number, '.') === false) { 25 $number_of_decimals = 0; 26 } else { 27 $number_of_decimals = strlen(substr($number, strpos($number, '.') + 1)); 28 } 29 30 if ($number_of_decimals > 0 && $number_of_decimals < $scale) { 31 $number = str_pad($number, $scale - $number_of_decimals, '0'); 32 } elseif ($number_of_decimals > $scale) { 33 $number = substr($number, 0, -($number_of_decimals - $scale)); 34 } 35 } 36 37 return $number; 38 } 39 40 /** 41 * @inheritdoc 42 */ 43 public function round($value, $precision = 0) 44 { 45 return number_format($value, $precision, '.', ''); 46 } 47 48 /** 49 * {@inheritdoc} 50 */ 51 public function equals($left_operand, $right_operand, $scale = null) 52 { 53 return $this->comp($left_operand, $right_operand, $scale) === 0; 54 } 55 56 /** 57 * This function fixes problems which occur when locale ist set to de_DE for example, 58 * because bc* function expecting strings 59 * @param mixed $number 60 * @return string 61 */ 62 protected function normalize($number) 63 { 64 if (null === $number) { 65 return $number; 66 } 67 68 $number = str_replace(' ', '', $number); 69 $number = $this->exp2dec($number); 70 $locale_info = localeconv(); 71 72 if ($locale_info['decimal_point'] != '.') { 73 $append = ''; 74 $number_of_decimals = (int) ini_get('precision') - (int) floor(log10(abs($number))); 75 if (0 > $number_of_decimals) { 76 $number *= pow(10, $number_of_decimals); 77 $append = str_repeat('0', -$number_of_decimals); 78 $number_of_decimals = 0; 79 } 80 81 return number_format($number, $number_of_decimals, '.', '') . $append; 82 } 83 84 return $number; 85 } 86 87 /** 88 * Moved from ilMath... 89 * Converts numbers in the form "1.5e4" into decimal notation 90 * @author Helmut Schottmüller <helmut.schottmueller@mac.com> 91 */ 92 protected function exp2dec($float_str) 93 { 94 // make sure its a standard php float string (i.e. change 0.2e+2 to 20) 95 // php will automatically format floats decimally if they are within a certain range 96 $original = $float_str; // store original float, so we can return a float keeping the pecision when possible 97 $float_str = (string) ((float) ($float_str)); 98 $float_str = str_replace(",", ".", $float_str); // convert ',' to '.' (float casting was locale sensitive) 99 100 // if there is an E in the float string 101 if (($pos = strpos(strtolower($float_str), 'e')) !== false) { 102 // get either side of the E, e.g. 1.6E+6 => exp E+6, num 1.6 103 $exp = substr($float_str, $pos + 1); 104 $num = substr($float_str, 0, $pos); 105 106 // strip off num sign, if there is one, and leave it off if its + (not required) 107 if ((($num_sign = $num[0]) === '+') || ($num_sign === '-')) { 108 $num = substr($num, 1); 109 } else { 110 $num_sign = ''; 111 } 112 if ($num_sign === '+') { 113 $num_sign = ''; 114 } 115 116 // strip off exponential sign ('+' or '-' as in 'E+6') if there is one, otherwise throw error, e.g. E+6 => '+' 117 if ((($exp_sign = $exp[0]) === '+') || ($exp_sign === '-')) { 118 $exp = substr($exp, 1); 119 } else { 120 trigger_error("Could not convert exponential notation to decimal notation: invalid float string '$float_str'", E_USER_ERROR); 121 } 122 123 // 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 124 $right_dec_places = (($dec_pos = strpos($num, '.')) === false) ? 0 : strlen(substr($num, $dec_pos + 1)); 125 // 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 126 $left_dec_places = ($dec_pos === false) ? strlen($num) : strlen(substr($num, 0, $dec_pos)); 127 128 // work out number of zeros from exp, exp sign and dec places, e.g. exp 6, exp sign +, dec places 1 => num zeros 5 129 if ($exp_sign === '+') { 130 $num_zeros = $exp - $right_dec_places; 131 } else { 132 $num_zeros = $exp - $left_dec_places; 133 } 134 135 // build a string with $num_zeros zeros, e.g. '0' 5 times => '00000' 136 $zeros = str_pad('', $num_zeros, '0'); 137 138 // strip decimal from num, e.g. 1.6 => 16 139 if ($dec_pos !== false) { 140 $num = str_replace('.', '', $num); 141 } 142 143 // if positive exponent, return like 1600000 144 if ($exp_sign === '+') { 145 return $num_sign . $num . $zeros; 146 } 147 // if negative exponent, return like 0.0000016 148 else { 149 return $num_sign . '0.' . $zeros . $num; 150 } 151 } 152 // otherwise, assume already in decimal notation and return 153 else { 154 return $original; 155 } 156 } 157} 158