Важно отметить, что я не ищу функцию округления. Я ищу функцию, которая возвращает число десятичных знаков в произвольном количестве, упрощенном десятичном представлении. То есть, мы имеем следующее:
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. Кто-нибудь из вас знает надежный способ получить точную точность после десятичной точки?
Цель этой функции, если кто-либо спросит, предназначен для использования в другой функции, которая преобразует float в упрощенную дробь (т.е. возвращает относительно единичный численный числитель и ненулевой естественный знаменатель). Единственный недостающий элемент этой внешней функции - это надежный способ определить количество десятичных знаков в поплавке, чтобы я мог умножить его на соответствующую мощность 10. Надеюсь, я его переусердствую.