diff --git a/core/lib/Drupal/Component/Utility/Number.php b/core/lib/Drupal/Component/Utility/Number.php index f8d7f0fbd9..6d7d5ee768 100644 --- a/core/lib/Drupal/Component/Utility/Number.php +++ b/core/lib/Drupal/Component/Utility/Number.php @@ -37,9 +37,13 @@ class Number { public static function normalize($number) { // Convert non-strings to strings, for consistent and lossless processing. if (is_float($number)) { + // If the float has less significant decimals than the number we can + // guarantee, convert it to a stirng directly. if (preg_match(sprintf('/^\d+\.\d{1,%d}$/', static::IEEE_754_DOUBLE_GUARANTEED_SIGNIFICANT_DECIMALS), (string) $number)) { return (string) $number; } + // For floats with more significant decimals than the number we can + // guarantee, discard the unguaranteed ones. return rtrim(number_format($number, self::IEEE_754_DOUBLE_GUARANTEED_SIGNIFICANT_DECIMALS, '.', ''), '0'); } elseif (is_int($number)) { @@ -92,7 +96,7 @@ public static function countSignificantDecimals($number) { * @param int|float|string $step * The step scale factor. Must be positive. If this is a string, it must be * formatted as an integer or a float. - * @param float $offset + * @param float|null $offset * (optional) An offset, to which the difference must be a multiple of the * given step. * @@ -101,12 +105,15 @@ public static function countSignificantDecimals($number) { * * @see http://opensource.apple.com/source/WebCore/WebCore-1298/html/NumberInputType.cpp */ - public static function validStep($value, $step, $offset = null) { + public static function validStep($value, $step, $offset = NULL) { // Confirm the step is positive. if ($step <= 0) { return FALSE; } + // Convert the value to a float so we can evaluate the precision later. + // Because subtracting the offset may change the value's precision, we only + // do so if it was set explicitly (is not null). $float_value = (float) abs(is_null($offset) ? $value : $value - $offset); // The expected number significant decimals is dictated by the step. diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php index 44ad5b4704..1b35b80738 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php @@ -102,6 +102,10 @@ public function getConstraints() { ] ], ]); + $constraints[] = $constraint_manager->create('Range', [ + 'min' => 0, + 'max' => Number::IEEE_754_DOUBLE_GUARANTEED_SIGNIFICANT_DECIMALS, + ]); return $constraints; } diff --git a/core/tests/Drupal/Tests/Component/Utility/NumberTest.php b/core/tests/Drupal/Tests/Component/Utility/NumberTest.php index 7cd2f050bc..b5e393629d 100644 --- a/core/tests/Drupal/Tests/Component/Utility/NumberTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/NumberTest.php @@ -167,7 +167,7 @@ public static function providerTestValidStep() { // Precision of the value is higher than that of the step. [990088999.0099, 0.001, FALSE], [990088999.0099, 0.01, FALSE], - + // Ensure floats with more significant decimals that the guaranteed // minimum are normalized. [0.00000000000000900009, 0.00000000000000100001, TRUE],