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 ConvertDecimal extends ConvertBase
   9  {
  10      const LARGEST_OCTAL_IN_DECIMAL = 536870911;
  11      const SMALLEST_OCTAL_IN_DECIMAL = -536870912;
  12      const LARGEST_BINARY_IN_DECIMAL = 511;
  13      const SMALLEST_BINARY_IN_DECIMAL = -512;
  14      const LARGEST_HEX_IN_DECIMAL = 549755813887;
  15      const SMALLEST_HEX_IN_DECIMAL = -549755813888;
  16  
  17      /**
  18       * toBinary.
  19       *
  20       * Return a decimal value as binary.
  21       *
  22       * Excel Function:
  23       *        DEC2BIN(x[,places])
  24       *
  25       * @param string $value The decimal integer you want to convert. If number is negative,
  26       *                          valid place values are ignored and DEC2BIN returns a 10-character
  27       *                          (10-bit) binary number in which the most significant bit is the sign
  28       *                          bit. The remaining 9 bits are magnitude bits. Negative numbers are
  29       *                          represented using two's-complement notation.
  30       *                      If number < -512 or if number > 511, DEC2BIN returns the #NUM! error
  31       *                          value.
  32       *                      If number is nonnumeric, DEC2BIN returns the #VALUE! error value.
  33       *                      If DEC2BIN requires more than places characters, it returns the #NUM!
  34       *                          error value.
  35       * @param int $places The number of characters to use. If places is omitted, DEC2BIN uses
  36       *                          the minimum number of characters necessary. Places is useful for
  37       *                          padding the return value with leading 0s (zeros).
  38       *                      If places is not an integer, it is truncated.
  39       *                      If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
  40       *                      If places is zero or negative, DEC2BIN returns the #NUM! error value.
  41       */
  42      public static function toBinary($value, $places = null): string
  43      {
  44          try {
  45              $value = self::validateValue(Functions::flattenSingleValue($value));
  46              $value = self::validateDecimal($value);
  47              $places = self::validatePlaces(Functions::flattenSingleValue($places));
  48          } catch (Exception $e) {
  49              return $e->getMessage();
  50          }
  51  
  52          $value = (int) floor((float) $value);
  53          if ($value > self::LARGEST_BINARY_IN_DECIMAL || $value < self::SMALLEST_BINARY_IN_DECIMAL) {
  54              return Functions::NAN();
  55          }
  56  
  57          $r = decbin($value);
  58          // Two's Complement
  59          $r = substr($r, -10);
  60  
  61          return self::nbrConversionFormat($r, $places);
  62      }
  63  
  64      /**
  65       * toHex.
  66       *
  67       * Return a decimal value as hex.
  68       *
  69       * Excel Function:
  70       *        DEC2HEX(x[,places])
  71       *
  72       * @param string $value The decimal integer you want to convert. If number is negative,
  73       *                          places is ignored and DEC2HEX returns a 10-character (40-bit)
  74       *                          hexadecimal number in which the most significant bit is the sign
  75       *                          bit. The remaining 39 bits are magnitude bits. Negative numbers
  76       *                          are represented using two's-complement notation.
  77       *                      If number < -549,755,813,888 or if number > 549,755,813,887,
  78       *                          DEC2HEX returns the #NUM! error value.
  79       *                      If number is nonnumeric, DEC2HEX returns the #VALUE! error value.
  80       *                      If DEC2HEX requires more than places characters, it returns the
  81       *                          #NUM! error value.
  82       * @param int $places The number of characters to use. If places is omitted, DEC2HEX uses
  83       *                          the minimum number of characters necessary. Places is useful for
  84       *                          padding the return value with leading 0s (zeros).
  85       *                      If places is not an integer, it is truncated.
  86       *                      If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
  87       *                      If places is zero or negative, DEC2HEX returns the #NUM! error value.
  88       */
  89      public static function toHex($value, $places = null): string
  90      {
  91          try {
  92              $value = self::validateValue(Functions::flattenSingleValue($value));
  93              $value = self::validateDecimal($value);
  94              $places = self::validatePlaces(Functions::flattenSingleValue($places));
  95          } catch (Exception $e) {
  96              return $e->getMessage();
  97          }
  98  
  99          $value = floor((float) $value);
 100          if ($value > self::LARGEST_HEX_IN_DECIMAL || $value < self::SMALLEST_HEX_IN_DECIMAL) {
 101              return Functions::NAN();
 102          }
 103          $r = strtoupper(dechex((int) $value));
 104          $r = self::hex32bit($value, $r);
 105  
 106          return self::nbrConversionFormat($r, $places);
 107      }
 108  
 109      public static function hex32bit(float $value, string $hexstr, bool $force = false): string
 110      {
 111          if (PHP_INT_SIZE === 4 || $force) {
 112              if ($value >= 2 ** 32) {
 113                  $quotient = (int) ($value / (2 ** 32));
 114  
 115                  return strtoupper(substr('0' . dechex($quotient), -2) . $hexstr);
 116              }
 117              if ($value < -(2 ** 32)) {
 118                  $quotient = 256 - (int) ceil((-$value) / (2 ** 32));
 119  
 120                  return strtoupper(substr('0' . dechex($quotient), -2) . substr("00000000$hexstr", -8));
 121              }
 122              if ($value < 0) {
 123                  return "FF$hexstr";
 124              }
 125          }
 126  
 127          return $hexstr;
 128      }
 129  
 130      /**
 131       * toOctal.
 132       *
 133       * Return an decimal value as octal.
 134       *
 135       * Excel Function:
 136       *        DEC2OCT(x[,places])
 137       *
 138       * @param string $value The decimal integer you want to convert. If number is negative,
 139       *                          places is ignored and DEC2OCT returns a 10-character (30-bit)
 140       *                          octal number in which the most significant bit is the sign bit.
 141       *                          The remaining 29 bits are magnitude bits. Negative numbers are
 142       *                          represented using two's-complement notation.
 143       *                      If number < -536,870,912 or if number > 536,870,911, DEC2OCT
 144       *                          returns the #NUM! error value.
 145       *                      If number is nonnumeric, DEC2OCT returns the #VALUE! error value.
 146       *                      If DEC2OCT requires more than places characters, it returns the
 147       *                          #NUM! error value.
 148       * @param int $places The number of characters to use. If places is omitted, DEC2OCT uses
 149       *                          the minimum number of characters necessary. Places is useful for
 150       *                          padding the return value with leading 0s (zeros).
 151       *                      If places is not an integer, it is truncated.
 152       *                      If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
 153       *                      If places is zero or negative, DEC2OCT returns the #NUM! error value.
 154       */
 155      public static function toOctal($value, $places = null): string
 156      {
 157          try {
 158              $value = self::validateValue(Functions::flattenSingleValue($value));
 159              $value = self::validateDecimal($value);
 160              $places = self::validatePlaces(Functions::flattenSingleValue($places));
 161          } catch (Exception $e) {
 162              return $e->getMessage();
 163          }
 164  
 165          $value = (int) floor((float) $value);
 166          if ($value > self::LARGEST_OCTAL_IN_DECIMAL || $value < self::SMALLEST_OCTAL_IN_DECIMAL) {
 167              return Functions::NAN();
 168          }
 169          $r = decoct($value);
 170          $r = substr($r, -10);
 171  
 172          return self::nbrConversionFormat($r, $places);
 173      }
 174  
 175      protected static function validateDecimal(string $value): string
 176      {
 177          if (strlen($value) > preg_match_all('/[-0123456789.]/', $value)) {
 178              throw new Exception(Functions::VALUE());
 179          }
 180  
 181          return $value;
 182      }
 183  }