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