我想要的是与 Number.prototype.toPrecision() 几乎相反的,这意味着当我有数字时,它有多少位小数?例如
(12.3456).getDecimals() // 4
对于任何想知道如何更快地完成此操作(无需转换为字符串)的人,这里有一个解决方案:
function precision(a) {
var e = 1;
while (Math.round(a * e) / e !== a) e *= 10;
return Math.log(e) / Math.LN10;
}
编辑:更完整的解决方案,涵盖边缘情况:
function precision(a) {
if (!isFinite(a)) return 0;
var e = 1, p = 0;
while (Math.round(a * e) / e !== a) { e *= 10; p++; }
return p;
}
一种可能的解决方案(取决于应用):
var precision = (12.3456 + "").split(".")[1].length;
如果“精度”指的是“小数位”,那么这是不可能的,因为浮点数是二进制的。它们没有有小数位,并且大多数具有少量小数位的值都具有二进制重复数字,并且当它们转换回十进制时,不一定会产生原始的十进制数。
任何处理浮点数“小数位”的代码都可能对某些数字产生意外的结果。
没有原生函数来确定小数位数。您可以做的是将数字转换为字符串,然后计算小数分隔符的偏移量
.
:
Number.prototype.getPrecision = function() {
var s = this + "",
d = s.indexOf('.') + 1;
return !d ? 0 : s.length - d;
};
(123).getPrecision() === 0;
(123.0).getPrecision() === 0;
(123.12345).getPrecision() === 5;
(1e3).getPrecision() === 0;
(1e-3).getPrecision() === 3;
但是花车的本质就是用来欺骗你的。
1
也可以用 0.00000000989
或其他东西来表示。我不确定上述内容在现实生活应用中实际表现如何。
基于@blackpla9ue评论并考虑数字指数格式:
function getPrecision (num) {
var numAsStr = num.toFixed(10); //number can be presented in exponential format, avoid it
numAsStr = numAsStr.replace(/0+$/g, '');
var precision = String(numAsStr).replace('.', '').length - num.toFixed().length;
return precision;
}
getPrecision(12.3456); //4
getPrecision(120.30003300000); //6, trailing zeros are truncated
getPrecision(15); //0
getPrecision(120.000)) //0
getPrecision(0.0000005); //7
getPrecision(-0.01)) //2
尝试以下方法
function countDecimalPlaces(number) {
var str = "" + number;
var index = str.indexOf('.');
if (index >= 0) {
return str.length - index - 1;
} else {
return 0;
}
}
基于@boolean_Type处理指数的方法,但避免使用正则表达式:
function getPrecision (value) {
if (!isFinite(value)) { return 0; }
const [int, float = ''] = Number(value).toFixed(12).split('.');
let precision = float.length;
while (float[precision - 1] === '0' && precision >= 0) precision--;
return precision;
}
这里有几个示例,一个使用库 (BigNumber.js),另一个不使用库。假设您要检查给定输入数字 (
inputNumber
) 的小数位数是否小于或等于最大小数位数 (tokenDecimals
)。
使用 BigNumber.js
import BigNumber from 'bignumber.js'; // ES6
// const BigNumber = require('bignumber.js').default; // CommonJS
const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Convert to BigNumber
const inputNumberBn = new BigNumber(inputNumber);
// BigNumber.js API Docs: http://mikemcl.github.io/bignumber.js/#dp
console.log(`Invalid?: ${inputNumberBn.dp() > tokenDecimals}`);
没有 BigNumber.js
function getPrecision(numberAsString) {
var n = numberAsString.toString().split('.');
return n.length > 1
? n[1].length
: 0;
}
const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Conversion of number to string returns scientific conversion
// So obtain the decimal places from the scientific notation value
const inputNumberDecimalPlaces = inputNumber.toString().split('-')[1];
// Use `toFixed` to convert the number to a string without it being
// in scientific notation and with the correct number decimal places
const inputNumberAsString = inputNumber.toFixed(inputNumberDecimalPlaces);
// Check if inputNumber is invalid due to having more decimal places
// than the permitted decimal places of the token
console.log(`Invalid?: ${getPrecision(inputNumberAsString) > tokenDecimals}`);
假设号码有效。
let number = 0.999;
let noOfPlaces = number.includes(".") //includes or contains
? number.toString().split(".").pop().length
: 0;
5.3M 操作/秒(慢 81.82%):
function precision (n) {
return (n.toString().split('.')[1] || '').length;
}
precision(1.0123456789)
29M 操作/秒(最快):
function precision (n) {
let e = 1;
let p = 0;
while (Math.round(n * e) / e !== n) {
e *= 10;
p++;
}
return p;
}
precision(1.0123456789);
这是一个简单的解决方案
首先,如果您传递一个简单的浮点值作为 12.1234,那么大多数下面/上面的逻辑可能会起作用,但如果您传递一个值作为 12.12340,那么它可能会排除 0 的计数。例如,如果该值是 12.12340那么它可能会给你一个结果 4 而不是 5。根据你的问题陈述,如果你要求 javascript 将你的浮点值分割并计数为 2 个整数,那么它不会包括它的尾随 0。
让我们用一个技巧来满足我们的要求;)
在下面的函数中,您需要传递一个字符串格式的值,它将完成您的工作
function getPrecision(value){
a = value.toString()
console.log('a ->',a)
b = a.split('.')
console.log('b->',b)
return b[1].length
getPrecision('12.12340') // Call a function
例如,运行以下逻辑
value = '12.12340'
a = value.toString()
b = a.split('.')
console.log('count of trailing decimals->',b[1].length)
就是这样!它将为您提供正常浮点值以及尾随 0 的浮点值的准确计数!
谢谢!
这个答案通过使函数更加健壮,补充了 Mourner 接受的解决方案。正如许多人指出的那样,浮点精度使得这样的函数不可靠。例如,
precision(0.1+0.2)
产生 17 而不是 1(这可能是特定于计算机的,但对于此示例,请参阅 https://jsfiddle.net/s0v17jby/5/)。
恕我直言,有两种方法可以解决这个问题: 1. 要么正确定义十进制类型,例如使用https://github.com/MikeMcl/decimal.js/,或者 2. 定义一个可接受的精度级别,这对于您的用例来说OK,并且对于 js 数字表示来说不是问题(8 个字节可以安全地表示)总共 16 位数字 AFAICT)。对于后一种解决方法,可以编写所提议函数的更强大的变体:
const MAX_DECIMAL_PRECISION = 9; /* must be <= 15 */
const maxDecimalPrecisionFloat = 10**MAX_DECIMAL_PRECISION;
function precisionRobust(a) {
if (!isFinite(a)) return 0;
var e = 1, p = 0;
while ( ++p<=MAX_DECIMAL_PRECISION && Math.round( ( Math.round(a * e) / e - a ) * maxDecimalPrecisionFloat ) !== 0) e *= 10;
return p-1;
}
在上面的示例中,最大精度为 9 意味着小数点前最多接受 6 位数字,小数点后最多接受 9 位(因此这适用于小于 100 万的数字,并且最多支持 9 位小数)。如果您的用例数量较小,那么您可以选择提高此精度(但最多为 15)。事实证明,为了计算精度,这个函数似乎对较大的数字也表现良好(尽管如果我们在 precisionRobust 函数中添加两个四舍五入的数字,情况就不再是这样了)。最后,由于我们现在知道最大可用精度,我们可以进一步避免无限循环(我无法复制,但似乎仍然会给某些人带来问题)。
decimal.js-light
包提供了.dp() ⇒ number 方法,它将返回小数位数。
x = new Decimal(1.234)
x.decimalPlaces() // '3'
y = new Decimal(987.654321)
y.dp() // '6'