如何在Javascript中获取浮点数的小数位?

问题描述 投票:0回答:13

我想要的是与 Number.prototype.toPrecision() 几乎相反的,这意味着当我有数字时,它有多少位小数?例如

(12.3456).getDecimals() // 4
javascript math floating-point
13个回答
62
投票

对于任何想知道如何更快地完成此操作(无需转换为字符串)的人,这里有一个解决方案:

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;
}

34
投票

一种可能的解决方案(取决于应用):

var precision = (12.3456 + "").split(".")[1].length;

4
投票

如果“精度”指的是“小数位”,那么这是不可能的,因为浮点数是二进制的。它们没有小数位,并且大多数具有少量小数位的值都具有二进制重复数字,并且当它们转换回十进制时,不一定会产生原始的十进制数。

任何处理浮点数“小数位”的代码都可能对某些数字产生意外的结果。


4
投票

没有原生函数来确定小数位数。您可以做的是将数字转换为字符串,然后计算小数分隔符的偏移量

.
:

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
或其他东西来表示。我不确定上述内容在现实生活应用中实际表现如何。


2
投票

基于@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

1
投票

尝试以下方法

function countDecimalPlaces(number) { 
  var str = "" + number;
  var index = str.indexOf('.');
  if (index >= 0) {
    return str.length - index - 1;
  } else {
    return 0;
  }
}

1
投票

基于@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;
}

1
投票

这里有几个示例,一个使用库 (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}`);

1
投票

假设号码有效。

let number = 0.999; 
let noOfPlaces = number.includes(".") //includes or contains
                        ? number.toString().split(".").pop().length
                        : 0;  

1
投票

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);

0
投票

这是一个简单的解决方案

首先,如果您传递一个简单的浮点值作为 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 的浮点值的准确计数!

谢谢!


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 函数中添加两个四舍五入的数字,情况就不再是这样了)。

最后,由于我们现在知道最大可用精度,我们可以进一步避免无限循环(我无法复制,但似乎仍然会给某些人带来问题)。


0
投票

decimal.js-light

 包提供了 
.dp() ⇒ number 方法,它将返回小数位数。

x = new Decimal(1.234) x.decimalPlaces() // '3' y = new Decimal(987.654321) y.dp() // '6'

runkit 游乐场

© www.soinside.com 2019 - 2024. All rights reserved.