8

我试过下面的示例代码

function sigFigs(n, sig) {
    if ( n === 0 )
        return 0
    var mult = Math.pow(10,
        sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
    return Math.round(n * mult) / mult;
 }

但是此功能不适用于 sigFigs(24730790,3) 返回 24699999.999999996 和 sigFigs(4.7152e-26,3) 返回:4.7200000000000004e-26 这样的输入

如果有人有工作示例,请分享。谢谢。

4

5 回答 5

21

您可以尝试 javascript 内置方法-

Number( my_number.toPrecision(3) )

对于您的情况,请尝试

Number( 24730790.0.toPrecision(5) )

对于您的参考和工作示例,您可以查看链接

于 2016-04-02T05:51:24.797 回答
5

首先感谢大家,如果没有共享这些片段,这将是一项艰巨的任务。

我的附加值是以下代码段(完整实现见下文)

parseFloat(number.toPrecision(precision))

请注意,如果数字是,例如,10000 并且精度是 2,那么number.toPrecision(precision)将是 '1.0e+4' 但parseFloat理解指数符号。

还值得一提的是,不管你信不信,Math.pow上面发布的算法使用和对数在测试用例上运行时formatNumber(5, 123456789)在 Mac(节点 v12)上运行成功,但在 Windows(节点 v10)上出现上升和错误。这很奇怪,所以我们得出了上面的解决方案。

最后,我利用这篇文章中提供的所有反馈,发现这是最终的实现。假设我们有一个formatNumber.js文件,其内容如下

/**
 * Format number to significant digits.
 *
 * @param {Number} precision
 * @param {Number} number
 *
 * @return {String} formattedValue
 */

export default function formatNumber (precision, number) {
  if (typeof number === 'undefined' || number === null) return ''

  if (number === 0) return '0'

  const roundedValue = round(precision, number)
  const floorValue = Math.floor(roundedValue)

  const isInteger = Math.abs(floorValue - roundedValue) < Number.EPSILON

  const numberOfFloorDigits = String(floorValue).length
  const numberOfDigits = String(roundedValue).length

  if (numberOfFloorDigits > precision) {
    return String(floorValue)
  } else {
    const padding = isInteger ? precision - numberOfFloorDigits : precision - numberOfDigits + 1

    if (padding > 0) {
      if (isInteger) {
        return `${String(floorValue)}.${'0'.repeat(padding)}`
      } else {
        return `${String(roundedValue)}${'0'.repeat(padding)}`
      }
    } else {
      return String(roundedValue)
    }
  }
}

function round (precision, number) {
  return parseFloat(number.toPrecision(precision))
}

如果您使用磁带进行测试,这里有一些基本测试

import test from 'tape'

import formatNumber from '..path/to/formatNumber.js'

test('formatNumber', (t) => {
  t.equal(formatNumber(4, undefined), '', 'undefined number returns an empty string')
  t.equal(formatNumber(4, null), '', 'null number return an empty string')

  t.equal(formatNumber(4, 0), '0')
  t.equal(formatNumber(4, 1.23456789), '1.235')
  t.equal(formatNumber(4, 1.23), '1.230')
  t.equal(formatNumber(4, 123456789), '123500000')
  t.equal(formatNumber(4, 1234567.890123), '1235000')
  t.equal(formatNumber(4, 123.4567890123), '123.5')
  t.equal(formatNumber(4, 12), '12.00')
  t.equal(formatNumber(4, 1.2), '1.200')
  t.equal(formatNumber(4, 1.234567890123), '1.235')
  t.equal(formatNumber(4, 0.001234567890), '0.001235')

  t.equal(formatNumber(5, 123456789), '123460000')

  t.end()
})
于 2019-10-21T22:30:00.840 回答
2

不幸的是,当数字 > 10 时,内置方法会给你带来愚蠢的结果,比如指数符号等。

我做了一个函数,它应该可以解决这个问题(也许不是最优雅的写法,但在这里):

function(value, precision) {
  if (value < 10) {
    value = parseFloat(value).toPrecision(precision)
  } else {
    value = parseInt(value)
    let significantValue = value
    for (let i = value.toString().length; i > precision; i--) {
      significantValue = Math.round(significantValue / 10)
    }
    for (let i = 0; significantValue.toString().length < value.toString().length; i++ ) {
      significantValue = significantValue * 10
    }
    value = significantValue
  }
  return value
}

如果您更喜欢使用指数表示法来表示较大的数字,请随意使用 toPrecision() 方法。

于 2019-08-30T13:47:24.090 回答
2

自动类型转换如何处理指数符号?

f = (x, n) => +x.toPrecision(n)

测试:

> f (0.123456789, 6)
0.123457
> f (123456789, 6)
123457000
> f (-123456789, 6)
-123457000
> f (-0.123456789, 6)
-0.123457
> f (-0.123456789, 2)
-0.12
> f (123456789, 2)
120000000

它返回一个数字而不是字符串。

于 2020-05-06T15:55:49.390 回答
0

如果要指定小数点左侧的有效数字并分别用 TBMK 替换无关的占位符

// example to 3 sigDigs (significant digits)
//54321 = 54.3M
//12300000 = 12.3M

const moneyFormat = (num, sigDigs) => {
   var s = num.toString();
   let nn = "";
   for (let i = 0; i <= s.length; i++) {
      if (s[i] !== undefined) {
         if (i < sigDigs) nn += s[i];
         else nn += "0";
      }
   }
   nn = nn
      .toString()
      .replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")
      .replace(",000,000,000", "B")
      .replace(",000,000", "M")
      .replace(",000", "k");
   if (
      nn[nn.length - 4] === "," &&
      nn[nn.length - 2] === "0" &&
      nn[nn.length - 1] === "0"
   ) {
      let numLetter = "K";
      if (parseInt(num) > 999999999999) numLetter = "T";
      else if (parseInt(num) > 999999999) numLetter = "B";
      else if (parseInt(num) > 999999) numLetter = "M";
      console.log("numLetter: " + numLetter);
      nn = nn.toString();
      let nn2 = ""; // new number 2
      for (let i = 0; i < nn.length - 4; i++) {
         nn2 += nn[i];
      }
      nn2 += "." + nn[nn.length - 3] + numLetter;
      nn = nn2;
   }

   return nn;
};
于 2020-10-16T00:00:47.847 回答