PageRenderTime 94ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/production/sql_schema_migrate/vendor/riimu/kit-phpencoder/src/Encoder/FloatEncoder.php

https://bitbucket.org/fastestsolution/dev_concitatech_cz
PHP | 148 lines | 80 code | 23 blank | 45 comment | 10 complexity | 58bdbd27c7b9a62d12bf65ef80865067 MD5 | raw file
Possible License(s): BSD-2-Clause, MIT
  1. <?php
  2. namespace Riimu\Kit\PHPEncoder\Encoder;
  3. /**
  4. * Encoder for float values.
  5. * @author Riikka Kalliomäki <riikka.kalliomaki@gmail.com>
  6. * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
  7. * @license http://opensource.org/licenses/mit-license.php MIT License
  8. */
  9. class FloatEncoder implements Encoder
  10. {
  11. /** The maximum value that can be accurately represented by a float */
  12. const FLOAT_MAX = 9007199254740992.0;
  13. /** @var array Default values for options in the encoder */
  14. private static $defaultOptions = [
  15. 'float.integers' => false,
  16. 'float.precision' => 17,
  17. 'float.export' => false,
  18. ];
  19. public function getDefaultOptions()
  20. {
  21. return self::$defaultOptions;
  22. }
  23. public function supports($value)
  24. {
  25. return \is_float($value);
  26. }
  27. public function encode($value, $depth, array $options, callable $encode)
  28. {
  29. if (is_nan($value)) {
  30. return 'NAN';
  31. } elseif (is_infinite($value)) {
  32. return $value < 0 ? '-INF' : 'INF';
  33. }
  34. return $this->encodeNumber($value, $options, $encode);
  35. }
  36. /**
  37. * Encodes the number as a PHP number representation.
  38. * @param float $float The number to encode
  39. * @param array $options The float encoding options
  40. * @param callable $encode Callback used to encode values
  41. * @return string The PHP code representation for the number
  42. */
  43. private function encodeNumber($float, array $options, callable $encode)
  44. {
  45. if ($this->isInteger($float, $options['float.integers'])) {
  46. return $this->encodeInteger($float, $encode);
  47. } elseif ($float === 0.0) {
  48. return '0.0';
  49. } elseif ($options['float.export']) {
  50. return var_export((float) $float, true);
  51. }
  52. return $this->encodeFloat($float, $this->determinePrecision($options));
  53. }
  54. /**
  55. * Tells if the number can be encoded as an integer.
  56. * @param float $float The number to test
  57. * @param bool|string $allowIntegers Whether integers should be allowed
  58. * @return bool True if the number can be encoded as an integer, false if not
  59. */
  60. private function isInteger($float, $allowIntegers)
  61. {
  62. if (!$allowIntegers || round($float) !== $float) {
  63. return false;
  64. } elseif (abs($float) < self::FLOAT_MAX) {
  65. return true;
  66. }
  67. return $allowIntegers === 'all';
  68. }
  69. /**
  70. * Encodes the given float as an integer.
  71. * @param float $float The number to encode
  72. * @param callable $encode Callback used to encode values
  73. * @return string The PHP code representation for the number
  74. */
  75. private function encodeInteger($float, callable $encode)
  76. {
  77. $minimum = \defined('PHP_INT_MIN') ? \PHP_INT_MIN : ~\PHP_INT_MAX;
  78. if ($float >= $minimum && $float <= \PHP_INT_MAX) {
  79. return $encode((int) $float);
  80. }
  81. return number_format($float, 0, '.', '');
  82. }
  83. /**
  84. * Determines the float precision based on the options.
  85. * @param array $options The float encoding options
  86. * @return int The precision used to encode floats
  87. */
  88. private function determinePrecision($options)
  89. {
  90. $precision = $options['float.precision'];
  91. if ($precision === false) {
  92. $precision = ini_get('serialize_precision');
  93. }
  94. return max(1, (int) $precision);
  95. }
  96. /**
  97. * Encodes the number using a floating point representation.
  98. * @param float $float The number to encode
  99. * @param int $precision The maximum precision of encoded floats
  100. * @return string The PHP code representation for the number
  101. */
  102. private function encodeFloat($float, $precision)
  103. {
  104. $log = (int) floor(log(abs($float), 10));
  105. if ($log > -5 && abs($float) < self::FLOAT_MAX && abs($log) < $precision) {
  106. return $this->formatFloat($float, $precision - $log - 1);
  107. }
  108. // Deal with overflow that results from rounding
  109. $log += (int) (round(abs($float) / 10 ** $log, $precision - 1) / 10);
  110. $string = $this->formatFloat($float / 10 ** $log, $precision - 1);
  111. return sprintf('%sE%+d', $string, $log);
  112. }
  113. /**
  114. * Formats the number as a decimal number.
  115. * @param float $float The number to format
  116. * @param int $digits The maximum number of decimal digits
  117. * @return string The number formatted as a decimal number
  118. */
  119. private function formatFloat($float, $digits)
  120. {
  121. $digits = max((int) $digits, 1);
  122. $string = rtrim(number_format($float, $digits, '.', ''), '0');
  123. return substr($string, -1) === '.' ? $string . '0' : $string;
  124. }
  125. }