Важно отметить, что я не ищу функцию округления. Я ищу функцию, которая возвращает количество десятичных знаков в упрощенном десятичном представлении произвольного числа. То есть имеем следующее:
decimalPlaces(5555.0); //=> 0
decimalPlaces(5555); //=> 0
decimalPlaces(555.5); //=> 1
decimalPlaces(555.50); //=> 1
decimalPlaces(0.0000005); //=> 7
decimalPlaces(5e-7); //=> 7
decimalPlaces(0.00000055); //=> 8
decimalPlaces(5.5e-7); //=> 8
Моим первым инстинктом было использование строковых представлений: разделить на '.'
, затем на 'e-'
и выполнить математику, как показано ниже (пример многословен):
function decimalPlaces(number) {
var parts = number.toString().split('.', 2),
integerPart = parts[0],
decimalPart = parts[1],
exponentPart;
if (integerPart.charAt(0) === '-') {
integerPart = integerPart.substring(1);
}
if (decimalPart !== undefined) {
parts = decimalPart.split('e-', 2);
decimalPart = parts[0];
}
else {
parts = integerPart.split('e-', 2);
integerPart = parts[0];
}
exponentPart = parts[1];
if (exponentPart !== undefined) {
return integerPart.length +
(decimalPart !== undefined ? decimalPart.length : 0) - 1 +
parseInt(exponentPart);
}
else {
return decimalPart !== undefined ? decimalPart.length : 0;
}
}
Для моих примеров выше, эта функция работает. Тем не менее, я не удовлетворен, пока не проверил все возможные значения, поэтому я отключился Number.MIN_VALUE
.
Number.MIN_VALUE; //=> 5e-324
decimalPlaces(Number.MIN_VALUE); //=> 324
Number.MIN_VALUE * 100; //=> 4.94e-322
decimalPlaces(Number.MIN_VALUE * 100); //=> 324
Сначала это выглядело разумно, но затем, сделав двойной дубль, я понял, что 5e-324 * 10
должно быть 5e-323
! И тут меня осенило: я имею дело с эффектами квантования очень маленьких чисел. Мало того, что числа квантуется перед хранением; кроме того, некоторые числа, хранящиеся в двоичном формате, имеют неоправданно длинные десятичные представления, поэтому их десятичные представления усекаются. Это прискорбно для меня, потому что это означает, что я не могу получить их истинную десятичную точность, используя их строковые представления.
Итак, я прихожу к вам, сообщество StackOverflow. Кто-нибудь из вас знает надежный способ получить истинную точность числа после запятой?
Назначение этой функции, если кто-нибудь спросит, предназначено для использования в другой функции, которая преобразует число с плавающей точкой в упрощенную дробь (то есть возвращает сравнительно простое целое число и ненулевой натуральный знаменатель). Единственная недостающая часть в этой внешней функции - это надежный способ определить количество десятичных разрядов в плавающей запятой, чтобы я мог умножить его на соответствующую степень 10. Надеюсь, я переосмыслил это.