我刚接触JavaScript,发现可以用toFixed()
和toPrecision()
对数字进行四舍五入处理。但是,我不知道这两者之间的区别。
number.toFixed()
和number.toPrecision()
有何区别?
我刚接触JavaScript,发现可以用toFixed()
和toPrecision()
对数字进行四舍五入处理。但是,我不知道这两者之间的区别。
number.toFixed()
和number.toPrecision()
有何区别?
toFixed(n)
提供小数点后 n
位长度;toPrecision(x)
提供总长度为 x
。
w3schools 上的参考链接:toFixed 和 toPrecision
为了完整起见,我应该提到编辑:
我之前了解到 w3schools 不是最好的资源,但是直到看到 kzh 的评论之前,我忘记了这个答案。这里还有来自 Mozilla Doc Center 的其他参考链接:关于toFixed()
和 关于toPrecision()
。幸运的是,MDC 和 w3schools 在这个问题上达成了一致。
toFixed()
等同于toFixed(0)
,而toPrecision()
只是返回原始数字而没有进行格式化。我认为前者给出了固定的小数位数,而后者给出了固定的有效数字位数。
Math.PI.toFixed(2); // "3.14"
Math.PI.toPrecision(2); // "3.1"
此外,如果一个数字的整数位数多于指定的精度,则toPrecision
将产生科学计数法。(Math.PI * 10).toPrecision(2); // "31"
(Math.PI * 100).toPrecision(2); // "3.1e+2"
编辑: 如果你是 JavaScript 初学者,我强烈推荐由道格拉斯·克罗福德所著的书籍“JavaScript: The Good Parts”。
(0.004).toPrecision(3) //'0.000400'
。我怀疑“给你固定数量的有效数字”并不是一个恰当的解释。 - Dmitry Koroliov例子很清晰:
var A = 123.456789;
A.toFixed() // 123
A.toFixed(0) // 123
A.toFixed(1) // 123.5 round up last
A.toFixed(2) // 123.46 round up last
A.toFixed(3) // 123.457 round up last
A.toFixed(4) // 123.4568 round up last
A.toFixed(5) // 123.45679 round up last
A.toFixed(6) // 123.456789
A.toFixed(7) // 123.4567890
A.toFixed(8) // 123.45678900
A.toFixed(9) // 123.456789000
A.toFixed(10) // 123.4567890000
A.toFixed(11) // 123.45678900000
A.toPrecision() // 123.456789
A.toPrecision(0) // --- ERROR ---
A.toPrecision(1) // 1e+2
A.toPrecision(2) // 1.2e+2
A.toPrecision(3) // 123
A.toPrecision(4) // 123.5 round up last
A.toPrecision(5) // 123.46 round up last
A.toPrecision(6) // 123.457 round up last
A.toPrecision(7) // 123.4568 round up last
A.toPrecision(8) // 123.45679 round up last
A.toPrecision(9) // 123.456789
A.toPrecision(10) // 123.4567890
A.toPrecision(11) // 123.45678900
// ----------------------
// edge-case rounding
// ----------------------
var B = 999.99;
B.toFixed(0) // 1000
B.toFixed(1) // 1000.0
B.toFixed(2) // 999.99
B.toFixed(3) // 999.990
B.toPrecision(0) // --- ERROR ----
B.toPrecision(1) // 1e+3
B.toPrecision(2) // 1.0e+3
B.toPrecision(3) // 1.00e+3
B.toPrecision(4) // 1000
B.toPrecision(5) // 999.99
B.toPrecision(6) // 999.990
var C = 0.99;
C.toFixed(0) // 1
C.toFixed(1) // 1.0
C.toFixed(2) // 0.99
C.toFixed(3) // 0.990
C.toPrecision(0) // --- ERROR ----
C.toPrecision(1) // 1
C.toPrecision(2) // 0.99
C.toPrecision(3) // 0.990
999.9
toPrecision(3)
-> 1.00e+3
这样的奇怪情况。这些情况不能适用于示例所展示的行为。 - Douglas Gaskell我认为最好用一个例子来回答这个问题。
假设您有以下数据:
var products = [
{
"title": "Really Nice Pen",
"price": 150
},
{
"title": "Golf Shirt",
"price": 49.99
},
{
"title": "My Car",
"price": 1234.56
}
]
您想以标题和格式化价格的方式显示每个产品。首先,让我们尝试使用toPrecision
:
document.write("The price of " + products[0].title + " is $" + products[0].price.toPrecision(5));
The price of Really Nice Pen is $150.00
看起来不错,所以您可能认为这也适用于其他产品:
document.write("The price of " + products[1].title + " is $" + products[2].price.toPrecision(5));
document.write("The price of " + products[2].title + " is $" + products[2].price.toPrecision(5));
The price of Golf Shirt is $49.990
The price of My Car is $1234.6
不太好。我们可以通过更改每个产品的有效数字位数来解决这个问题,但是如果我们正在迭代产品数组,那可能会很棘手。让我们改用toFixed
:
document.write("The price of " + products[0].title + " is $" + products[0].price.toFixed(2));
document.write("The price of " + products[1].title + " is $" + products[2].price.toFixed(2));
document.write("The price of " + products[2].title + " is $" + products[2].price.toFixed(2));
The price of Really Nice Pen is $150.00
The price of Golf Shirt is $49.99
The price of My Car is $1234.56
这会得到您预期的结果,没有猜测的成分,也没有四舍五入。
只需:
49.99.toFixed(5)
// → "49.99000"
49.99.toPrecision(5)
// → "49.990"
toPrecision()
会返回科学计数法,而 toFixed()
则不会。a = 999999999999999934464;
,a.toFixed(0)
返回"1e+21"
。也许更准确的答案是,除非toString()返回指数符号,否则toFixed()不会返回指数符号。 - the paultoFixed(fractionDigits?)
已经在其他答案中被解释得比较准确:
fractionDigits
[位]数字:例如:
(-3).toFixed(1) // '-3.0'
(-3).toFixed(0) // '-3'
(-3).toFixed() // '-3'
(-0.03).toFixed(1) // '-0.0'
toPrecision(precision?)
在之前的回答中没有被正确描述,因此需要注意。此外,我要添加一个免责声明,即我无法理解toPrecision
的规范,因此下面的内容是基于在Node.js中测试实现的尝试和错误方法得出的结论。这些步骤并不涵盖所有的边界情况,比如数字是NaN、精度参数不是整数或小于1或大于100等等。这是为了避免让解释变得混乱,因为规范似乎很复杂。
*列表中保留了案例编号,尽管某些案例可能与其他案例相似,但它们必须展示特定的行为
precision
以指数表示法表示数字,其中precision
是有效数字中的位数,例如情况1:
0.000004
→ 精度 = 3 →400 * 10^-8
情况2:0.0000004
→ 精度 = 3 →400 * 10^-9
情况3:123
→ 精度 = 1 →1.23 * 10^2
情况4:153
→ 精度 = 1 →1.53 * 10^2
情况5:1234.56
→ 精度 = 3 →123.456 * 10^1
情况6:1234.56
→ 精度 = 5 →12345.6 * 10^-1
情况1:
400 * 10^-8
→400 * 10^-8
(没有分数,没有变化)
情况2:400 * 10^-9
→400 * 10^-9
(与情况1的推理相同)
情况3:1.23 * 10^2
→1 * 10^2
(1.23
四舍五入为1
)
情况4:1.53 * 10^2
→2 * 10^2
(1.53
四舍五入为2
)
情况5:123.456 * 10^1
→123 * 10^1
(也进行了四舍五入)
情况6:12345.6 * 10^-1
→12346 * 10^-1
(四舍五入)
3a) 保留步骤2中有效数字中的所有数字
3b) 如果 precision
< 点前面的数字数量(在“正常”即十进制表示中),则使用指数符号表示
情况3:
1 * 10^2
→'1e+2'
(数字现在为100
,有3位数字,精度为1,使用指数)
情况4:2 * 10^2
→'2e+2'
(数字现在为200
,有3位数字,精度为1,使用指数)
情况5:123 * 10^1
→'1.23e+3'
(数字现在为1230
,有4位数字,精度为3,使用指数; 请注意,有效数字从第2步中保留了所有数字:123
变为1.23
)
3c) 如果数字的整数部分为0,并且小数点后面到第一个有效数字之间的零的数量>5,则使用指数表示法。
案例2:
400 * 10^-9
→'4.00e-7'
(数字为0.0000004,它有整数部分0
,小数点后面有>5个零,请注意,来自400 * 10^-9
的两个零已被保留)
3d) 如果数字的整数部分为0且小数点右侧的零的数量<=5,则使用十进制表示法,但将从步骤2中的有效数字中保留数字
案例1:
400 * 10^-8
→'0.00000400'
(有效数字部分的两个零已被保留)
3e) 如果精度
>=十进制表示中小数点前的数字数量,则使用十进制表示法。
12346 * 10^-1
→ 1234.6
(步骤2中数字的小数形式为1234.6,精度为5,小数点前的数字个数为4,字符串使用十进制表示法,步骤2中的有效数字全部被保留)。
console.log((0.000004).toPrecision(3));
console.log((0.0000004).toPrecision(3));
console.log((123).toPrecision(1));
console.log((153).toPrecision(1));
console.log((1234.56).toPrecision(3));
console.log((1234.56).toPrecision(5));
999.9
toPrecisison(3)
输出时会变成 1.00e+3
而不是 999
或者 1
...我们该如何绕过这种情况呢? - Douglas GaskelltoPrecision()
和toFixed()
都是用于在打印数字之前格式化数字的函数。因此,它们都返回String
值。
但有一个例外。如果您将这些函数用于负数数字文字,由于运算符优先级,将返回一个数字。这意味着toFixed()
或toPrecision()
首先会返回一个字符串,然后减号运算符将该字符串转换回数字作为负值。请参见下面的示例。
toPrecision()
返回一个表示Number对象的字符串,该字符串采用固定点或指数表示法舍入到有效数字。因此,如果您指定要精确到1,则它将返回第一个有效数字以及科学计数法来表示10的幂或其小数点之前的前一个0(如果有效数字<0)。
const num1 = 123.4567;
// if no arguments are passed, it is similar to converting the Number to String
num1.toPrecision(); // returns "123.4567
// scientific notation is used when you pass precision count less than total
// number of digits left of the period
num1.toPrecision(2); // returns "1.2e+2"
// last digit is rounded if precision is less than total significant digits
num1.toPrecision(4); // returns "123.5"
num1.toPrecision(5); // returns "123.46"
const largeNum = 456.789;
largeNum.toPrecision(2); // returns "4.6e+2"
// trailing zeroes are added if precision is > total digits of the number or float
num1.toPrecision(9); // returns "123.456700"
const num2 = 123;
num2.toPrecision(4); // returns "123.0"
const num3 = 0.00123;
num3.toPrecision(4); // returns "0.001230"
num3.toPrecision(5); // returns "0.0012300"
// if the number is < 1, precision is by the significant digits
num3.toPrecision(1); // returns "0.001"
toFixed()
返回一个表示数字对象以定点表示法舍入后的字符串。此函数仅关注小数点后的数字。
const num1 = 123.4567;
// if no argument is passed, the fractions are removed
num1.toFixed(); // returns "123"
// specifying an argument means you the amount of numbers after the decimal point
num1.toFixed(1); // returns "123.5"
num1.toFixed(3); // returns "123.457"
num1.toFixed(5); // returns "123.45670"
num1.toFixed(7); // returns "123.4567000"
// trying to operator on number literals
2.34.toFixed(1); // returns "2.3"
2.toFixed(1); // returns SyntaxError
(2).toFixed(1); // returns "2.0"
(2.34e+5).toFixed(1); // returns "234000.0"
我之前提到过一个例外情况,即在负数字面量上使用这些函数将返回一个数字而不是字符串,这是由于运算符优先级的影响。以下是一些示例:
// Note: these are returning as Number
// toPrecision()
-123.45.toPrecision(); // returns -123.45
-123.45.toPrecision(2); // returns -120
-123.45.toPrecision(4); // returns -123.5
-2.34e+2.toPrecision(1); // returns -200
-0.0456.toPrecision(1); // returns -0.05
-0.0456.toPrecision(6); // returns -0.0456
// toFixed()
-123.45.toFixed(); // returns -123.45
-123.45.toFixed(1); // returns -123.5
-123.45.toFixed(4); // returns -123.45
-0.0456.toFixed(1); // returns -0
-0.0456.toFixed(6); // -0.0456
有趣的事实:从-0.0456.toFixed(1)
中可以看到有符号的零
参见:+0和-0是相同的吗?
toPrecision(x)
并不是“提供x
的总长度”,而是按照给定的有效数字格式化数字。例如,0.0000022.toPrecision(1)
将返回0.000002
。 - Andy E