ConvertOctal.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
  3. use PhpOffice\PhpSpreadsheet\Calculation\Exception;
  4. use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
  5. class ConvertOctal extends ConvertBase
  6. {
  7. /**
  8. * toBinary.
  9. *
  10. * Return an octal value as binary.
  11. *
  12. * Excel Function:
  13. * OCT2BIN(x[,places])
  14. *
  15. * @param array|string $value The octal number you want to convert. Number may not
  16. * contain more than 10 characters. The most significant
  17. * bit of number is the sign bit. The remaining 29 bits
  18. * are magnitude bits. Negative numbers are represented
  19. * using two's-complement notation.
  20. * If number is negative, OCT2BIN ignores places and returns
  21. * a 10-character binary number.
  22. * If number is negative, it cannot be less than 7777777000,
  23. * and if number is positive, it cannot be greater than 777.
  24. * If number is not a valid octal number, OCT2BIN returns
  25. * the #NUM! error value.
  26. * If OCT2BIN requires more than places characters, it
  27. * returns the #NUM! error value.
  28. * Or can be an array of values
  29. * @param array|int $places The number of characters to use. If places is omitted,
  30. * OCT2BIN uses the minimum number of characters necessary.
  31. * Places is useful for padding the return value with
  32. * leading 0s (zeros).
  33. * If places is not an integer, it is truncated.
  34. * If places is nonnumeric, OCT2BIN returns the #VALUE!
  35. * error value.
  36. * If places is negative, OCT2BIN returns the #NUM! error
  37. * value.
  38. * Or can be an array of values
  39. *
  40. * @return array|string Result, or an error
  41. * If an array of numbers is passed as an argument, then the returned result will also be an array
  42. * with the same dimensions
  43. */
  44. public static function toBinary($value, $places = null)
  45. {
  46. if (is_array($value) || is_array($places)) {
  47. return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
  48. }
  49. try {
  50. $value = self::validateValue($value);
  51. $value = self::validateOctal($value);
  52. $places = self::validatePlaces($places);
  53. } catch (Exception $e) {
  54. return $e->getMessage();
  55. }
  56. return ConvertDecimal::toBinary(self::toDecimal($value), $places);
  57. }
  58. /**
  59. * toDecimal.
  60. *
  61. * Return an octal value as decimal.
  62. *
  63. * Excel Function:
  64. * OCT2DEC(x)
  65. *
  66. * @param array|string $value The octal number you want to convert. Number may not contain
  67. * more than 10 octal characters (30 bits). The most significant
  68. * bit of number is the sign bit. The remaining 29 bits are
  69. * magnitude bits. Negative numbers are represented using
  70. * two's-complement notation.
  71. * If number is not a valid octal number, OCT2DEC returns the
  72. * #NUM! error value.
  73. * Or can be an array of values
  74. *
  75. * @return array|string Result, or an error
  76. * If an array of numbers is passed as an argument, then the returned result will also be an array
  77. * with the same dimensions
  78. */
  79. public static function toDecimal($value)
  80. {
  81. if (is_array($value)) {
  82. return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
  83. }
  84. try {
  85. $value = self::validateValue($value);
  86. $value = self::validateOctal($value);
  87. } catch (Exception $e) {
  88. return $e->getMessage();
  89. }
  90. $binX = '';
  91. foreach (str_split($value) as $char) {
  92. $binX .= str_pad(decbin((int) $char), 3, '0', STR_PAD_LEFT);
  93. }
  94. if (strlen($binX) == 30 && $binX[0] == '1') {
  95. for ($i = 0; $i < 30; ++$i) {
  96. $binX[$i] = ($binX[$i] == '1' ? '0' : '1');
  97. }
  98. return (string) ((bindec($binX) + 1) * -1);
  99. }
  100. return (string) bindec($binX);
  101. }
  102. /**
  103. * toHex.
  104. *
  105. * Return an octal value as hex.
  106. *
  107. * Excel Function:
  108. * OCT2HEX(x[,places])
  109. *
  110. * @param array|string $value The octal number you want to convert. Number may not contain
  111. * more than 10 octal characters (30 bits). The most significant
  112. * bit of number is the sign bit. The remaining 29 bits are
  113. * magnitude bits. Negative numbers are represented using
  114. * two's-complement notation.
  115. * If number is negative, OCT2HEX ignores places and returns a
  116. * 10-character hexadecimal number.
  117. * If number is not a valid octal number, OCT2HEX returns the
  118. * #NUM! error value.
  119. * If OCT2HEX requires more than places characters, it returns
  120. * the #NUM! error value.
  121. * Or can be an array of values
  122. * @param array|int $places The number of characters to use. If places is omitted, OCT2HEX
  123. * uses the minimum number of characters necessary. Places is useful
  124. * for padding the return value with leading 0s (zeros).
  125. * If places is not an integer, it is truncated.
  126. * If places is nonnumeric, OCT2HEX returns the #VALUE! error value.
  127. * If places is negative, OCT2HEX returns the #NUM! error value.
  128. * Or can be an array of values
  129. *
  130. * @return array|string Result, or an error
  131. * If an array of numbers is passed as an argument, then the returned result will also be an array
  132. * with the same dimensions
  133. */
  134. public static function toHex($value, $places = null)
  135. {
  136. if (is_array($value) || is_array($places)) {
  137. return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
  138. }
  139. try {
  140. $value = self::validateValue($value);
  141. $value = self::validateOctal($value);
  142. $places = self::validatePlaces($places);
  143. } catch (Exception $e) {
  144. return $e->getMessage();
  145. }
  146. $hexVal = strtoupper(dechex((int) self::toDecimal($value)));
  147. $hexVal = (PHP_INT_SIZE === 4 && strlen($value) === 10 && $value[0] >= '4') ? "FF{$hexVal}" : $hexVal;
  148. return self::nbrConversionFormat($hexVal, $places);
  149. }
  150. protected static function validateOctal(string $value): string
  151. {
  152. $numDigits = (int) preg_match_all('/[01234567]/', $value);
  153. if (strlen($value) > $numDigits || $numDigits > 10) {
  154. throw new Exception(ExcelError::NAN());
  155. }
  156. return $value;
  157. }
  158. }