Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

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