Differences Between: [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; 4 5 use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; 6 use PhpOffice\PhpSpreadsheet\Calculation\Exception; 7 use PhpOffice\PhpSpreadsheet\Calculation\Functions; 8 use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 9 10 class BitWise 11 { 12 use ArrayEnabled; 13 14 const SPLIT_DIVISOR = 2 ** 24; 15 16 /** 17 * Split a number into upper and lower portions for full 32-bit support. 18 * 19 * @param float|int $number 20 * 21 * @return int[] 22 */ 23 private static function splitNumber($number): array 24 { 25 return [(int) floor($number / self::SPLIT_DIVISOR), (int) fmod($number, self::SPLIT_DIVISOR)]; 26 } 27 28 /** 29 * BITAND. 30 * 31 * Returns the bitwise AND of two integer values. 32 * 33 * Excel Function: 34 * BITAND(number1, number2) 35 * 36 * @param array|int $number1 37 * Or can be an array of values 38 * @param array|int $number2 39 * Or can be an array of values 40 * 41 * @return array|int|string 42 * If an array of numbers is passed as an argument, then the returned result will also be an array 43 * with the same dimensions 44 */ 45 public static function BITAND($number1, $number2) 46 { 47 if (is_array($number1) || is_array($number2)) { 48 return self::evaluateArrayArguments([self::class, __FUNCTION__], $number1, $number2); 49 } 50 51 try { 52 $number1 = self::validateBitwiseArgument($number1); 53 $number2 = self::validateBitwiseArgument($number2); 54 } catch (Exception $e) { 55 return $e->getMessage(); 56 } 57 $split1 = self::splitNumber($number1); 58 $split2 = self::splitNumber($number2); 59 60 return self::SPLIT_DIVISOR * ($split1[0] & $split2[0]) + ($split1[1] & $split2[1]); 61 } 62 63 /** 64 * BITOR. 65 * 66 * Returns the bitwise OR of two integer values. 67 * 68 * Excel Function: 69 * BITOR(number1, number2) 70 * 71 * @param array|int $number1 72 * Or can be an array of values 73 * @param array|int $number2 74 * Or can be an array of values 75 * 76 * @return array|int|string 77 * If an array of numbers is passed as an argument, then the returned result will also be an array 78 * with the same dimensions 79 */ 80 public static function BITOR($number1, $number2) 81 { 82 if (is_array($number1) || is_array($number2)) { 83 return self::evaluateArrayArguments([self::class, __FUNCTION__], $number1, $number2); 84 } 85 86 try { 87 $number1 = self::validateBitwiseArgument($number1); 88 $number2 = self::validateBitwiseArgument($number2); 89 } catch (Exception $e) { 90 return $e->getMessage(); 91 } 92 93 $split1 = self::splitNumber($number1); 94 $split2 = self::splitNumber($number2); 95 96 return self::SPLIT_DIVISOR * ($split1[0] | $split2[0]) + ($split1[1] | $split2[1]); 97 } 98 99 /** 100 * BITXOR. 101 * 102 * Returns the bitwise XOR of two integer values. 103 * 104 * Excel Function: 105 * BITXOR(number1, number2) 106 * 107 * @param array|int $number1 108 * Or can be an array of values 109 * @param array|int $number2 110 * Or can be an array of values 111 * 112 * @return array|int|string 113 * If an array of numbers is passed as an argument, then the returned result will also be an array 114 * with the same dimensions 115 */ 116 public static function BITXOR($number1, $number2) 117 { 118 if (is_array($number1) || is_array($number2)) { 119 return self::evaluateArrayArguments([self::class, __FUNCTION__], $number1, $number2); 120 } 121 122 try { 123 $number1 = self::validateBitwiseArgument($number1); 124 $number2 = self::validateBitwiseArgument($number2); 125 } catch (Exception $e) { 126 return $e->getMessage(); 127 } 128 129 $split1 = self::splitNumber($number1); 130 $split2 = self::splitNumber($number2); 131 132 return self::SPLIT_DIVISOR * ($split1[0] ^ $split2[0]) + ($split1[1] ^ $split2[1]); 133 } 134 135 /** 136 * BITLSHIFT. 137 * 138 * Returns the number value shifted left by shift_amount bits. 139 * 140 * Excel Function: 141 * BITLSHIFT(number, shift_amount) 142 * 143 * @param array|int $number 144 * Or can be an array of values 145 * @param array|int $shiftAmount 146 * Or can be an array of values 147 * 148 * @return array|float|int|string 149 * If an array of numbers is passed as an argument, then the returned result will also be an array 150 * with the same dimensions 151 */ 152 public static function BITLSHIFT($number, $shiftAmount) 153 { 154 if (is_array($number) || is_array($shiftAmount)) { 155 return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $shiftAmount); 156 } 157 158 try { 159 $number = self::validateBitwiseArgument($number); 160 $shiftAmount = self::validateShiftAmount($shiftAmount); 161 } catch (Exception $e) { 162 return $e->getMessage(); 163 } 164 165 $result = floor($number * (2 ** $shiftAmount)); 166 if ($result > 2 ** 48 - 1) { 167 return ExcelError::NAN(); 168 } 169 170 return $result; 171 } 172 173 /** 174 * BITRSHIFT. 175 * 176 * Returns the number value shifted right by shift_amount bits. 177 * 178 * Excel Function: 179 * BITRSHIFT(number, shift_amount) 180 * 181 * @param array|int $number 182 * Or can be an array of values 183 * @param array|int $shiftAmount 184 * Or can be an array of values 185 * 186 * @return array|float|int|string 187 * If an array of numbers is passed as an argument, then the returned result will also be an array 188 * with the same dimensions 189 */ 190 public static function BITRSHIFT($number, $shiftAmount) 191 { 192 if (is_array($number) || is_array($shiftAmount)) { 193 return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $shiftAmount); 194 } 195 196 try { 197 $number = self::validateBitwiseArgument($number); 198 $shiftAmount = self::validateShiftAmount($shiftAmount); 199 } catch (Exception $e) { 200 return $e->getMessage(); 201 } 202 203 $result = floor($number / (2 ** $shiftAmount)); 204 if ($result > 2 ** 48 - 1) { // possible because shiftAmount can be negative 205 return ExcelError::NAN(); 206 } 207 208 return $result; 209 } 210 211 /** 212 * Validate arguments passed to the bitwise functions. 213 * 214 * @param mixed $value 215 * 216 * @return float 217 */ 218 private static function validateBitwiseArgument($value) 219 { 220 $value = self::nullFalseTrueToNumber($value); 221 222 if (is_numeric($value)) { 223 $value = (float) $value; 224 if ($value == floor($value)) { 225 if (($value > 2 ** 48 - 1) || ($value < 0)) { 226 throw new Exception(ExcelError::NAN()); 227 } 228 229 return floor($value); 230 } 231 232 throw new Exception(ExcelError::NAN()); 233 } 234 235 throw new Exception(ExcelError::VALUE()); 236 } 237 238 /** 239 * Validate arguments passed to the bitwise functions. 240 * 241 * @param mixed $value 242 * 243 * @return int 244 */ 245 private static function validateShiftAmount($value) 246 { 247 $value = self::nullFalseTrueToNumber($value); 248 249 if (is_numeric($value)) { 250 if (abs($value) > 53) { 251 throw new Exception(ExcelError::NAN()); 252 } 253 254 return (int) $value; 255 } 256 257 throw new Exception(ExcelError::VALUE()); 258 } 259 260 /** 261 * Many functions accept null/false/true argument treated as 0/0/1. 262 * 263 * @param mixed $number 264 * 265 * @return mixed 266 */ 267 private static function nullFalseTrueToNumber(&$number) 268 { 269 if ($number === null) { 270 $number = 0; 271 } elseif (is_bool($number)) { 272 $number = (int) $number; 273 } 274 275 return $number; 276 } 277 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body