Mercurial > hg > isophonics-drupal-site
diff core/lib/Drupal/Component/Utility/Number.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/lib/Drupal/Component/Utility/Number.php Wed Nov 29 16:09:58 2017 +0000 @@ -0,0 +1,101 @@ +<?php + +namespace Drupal\Component\Utility; + +/** + * Provides helper methods for manipulating numbers. + * + * @ingroup utility + */ +class Number { + + /** + * Verifies that a number is a multiple of a given step. + * + * The implementation assumes it is dealing with IEEE 754 double precision + * floating point numbers that are used by PHP on most systems. + * + * This is based on the number/range verification methods of webkit. + * + * @param float $value + * The value that needs to be checked. + * @param float $step + * The step scale factor. Must be positive. + * @param float $offset + * (optional) An offset, to which the difference must be a multiple of the + * given step. + * + * @return bool + * TRUE if no step mismatch has occurred, or FALSE otherwise. + * + * @see http://opensource.apple.com/source/WebCore/WebCore-1298/html/NumberInputType.cpp + */ + public static function validStep($value, $step, $offset = 0.0) { + $double_value = (double) abs($value - $offset); + + // The fractional part of a double has 53 bits. The greatest number that + // could be represented with that is 2^53. If the given value is even bigger + // than $step * 2^53, then dividing by $step will result in a very small + // remainder. Since that remainder can't even be represented with a single + // precision float the following computation of the remainder makes no sense + // and we can safely ignore it instead. + if ($double_value / pow(2.0, 53) > $step) { + return TRUE; + } + + // Now compute that remainder of a division by $step. + $remainder = (double) abs($double_value - $step * round($double_value / $step)); + + // $remainder is a double precision floating point number. Remainders that + // can't be represented with single precision floats are acceptable. The + // fractional part of a float has 24 bits. That means remainders smaller than + // $step * 2^-24 are acceptable. + $computed_acceptable_error = (double) ($step / pow(2.0, 24)); + + return $computed_acceptable_error >= $remainder || $remainder >= ($step - $computed_acceptable_error); + } + + /** + * Generates a sorting code from an integer. + * + * Consists of a leading character indicating length, followed by N digits + * with a numerical value in base 36 (alphadecimal). These codes can be sorted + * as strings without altering numerical order. + * + * It goes: + * 00, 01, 02, ..., 0y, 0z, + * 110, 111, ... , 1zy, 1zz, + * 2100, 2101, ..., 2zzy, 2zzz, + * 31000, 31001, ... + * + * @param int $i + * The integer value to convert. + * + * @return string + * The alpha decimal value. + * + * @see \Drupal\Component\Utility\Number::alphadecimalToInt + */ + public static function intToAlphadecimal($i = 0) { + $num = base_convert((int) $i, 10, 36); + $length = strlen($num); + + return chr($length + ord('0') - 1) . $num; + } + + /** + * Decodes a sorting code back to an integer. + * + * @param string $string + * The alpha decimal value to convert + * + * @return int + * The integer value. + * + * @see \Drupal\Component\Utility\Number::intToAlphadecimal + */ + public static function alphadecimalToInt($string = '00') { + return (int) base_convert(substr($string, 1), 36, 10); + } + +}