使用JavaScript获取数字的小数部分

361

我有像 3.21.6 这样的浮点数。

我需要将这个数字分离成整数和小数两部分。例如,值为 3.2 的数字将被拆分为两个数字,即 30.2

获取整数部分很容易:

n = Math.floor(n);

但是我在获取小数部分时遇到了问题。 我尝试过这个:

remainder = n % 2; //obtem a parte decimal do rating

但它并不总是正确的工作。

先前的代码产生以下输出:

n = 3.1 // gives remainder = 1.1

我这里缺少了什么?


2
请注意,n = Math.floor(n); 仅适用于非负数,以返回您所需的结果(整数部分)。 - tsemer
请使用“%1”而不是“%2”来简化操作。 - masterxilo
4
decimalPart = number - Math.floor(number) 可以翻译为:小数部分等于数字减去向下取整后的结果。此外,你可以增加精度。parseFloat(decimalPart.toPrecision(3))表示保留 3 位小数的浮点数。 - Abhishek Chandel
要获取浮点数的整数部分,请使用Math.trunc(),而不是Math.floor()。 - undefined
33个回答

486

使用1,而不是2

js> 2.3 % 1
0.2999999999999998

100
在一个把0.2999999999999998等同于0.3的世界里,这可能是可以接受的。但对我而言,不是这样的。因此,为了解决这个问题,我会避免使用Math.*%操作符。 - Marcel Stör
84
为了避免浮点数舍入问题,可以使用 toFixed 方法来解决,例如 (2.3 % 1).toFixed(4) == "0.3000"。该方法在某些情况下能够帮助使结果更准确,并且不改变原有意义。 - Brian M. Hunt
22
(2.3 % 1).toFixed(4).substring(2) = "3000",如果您不需要包含 0.,则可以这么写。本代码的作用是将数值 2.3 取模后保留四位小数,并从第三位字符开始截取字符串,最终结果为 "3000" - Simon_Weaver
31
在一个数字为“2.3”的世界里,而不是“2”或“3”,即使看起来很难看,数字“0.2999999999999998”也是完全可以接受的。请注意,不要改变原意并尽可能保持通俗易懂。 - Gershom Maes
12
@GershomMaes,有许多情况下这个数字是不能被接受的。 - Adam Leggett
显示剩余11条评论

137
var decimal = n - Math.floor(n)

虽然这对负数不起作用,所以我们可能需要做些调整

n = Math.abs(n); // Change to positive
var decimal = n - Math.floor(n)

如果您已经有整数部分,就不需要再调用 Math.floor() 了--只需使用您计算出的整数部分即可。 - tvanfosson
6
var n = 3.2, integr = Math.floor(n), decimal = n - integr; 只使用一次 _Math.floor()_。 integr = 3; decimal = 0.20000000000000018; - Nurlan
5
为了使用负数,只需要将Math.floor替换为Math.trunc即可。 - Igor Silva
这段代码返回的数字并不是我期望的精确数字,例如从100.80中期望得到0.80,而不是0.79999... 为了解决这个问题,我添加了decimal.toFixed(2)。 - Luis Febro

100

你可以将其转换为字符串,对吗?

n = (n + "").split(".");

30
除欧洲大陆外,这个方法在其他地方都能正常工作,因为欧洲使用逗号“,”作为小数点分隔符。如果你有跨国业务并且目标市场是欧洲,记得考虑这一点,因为这种解决方案对他们来说效果不佳。 - cdmdotnet
20
我来自欧洲大陆,使用法国版的Firefox浏览器,并且它能够正常使用。在法国通常,我们使用逗号作为十进制分隔符。原因是在JavaScript中将数字转换为字符串时不涉及任何文化差异,尽管我更喜欢使用n.toString()而不是n + "",因为它更易读。 - Gabriel Hautclocq
5
如果速度很重要,那么 n + "" 确实更好(参见 https://jsperf.com/number-vs-number-tostring-vs-string-number)。 - Gabriel Hautclocq
2
@cdmdotnet JS使用“.”作为小数分隔符,因此如果您的输入变量类型为浮点型,则无论在哪里都可以正常工作。只有当您的输入为字符串时才需要处理该问题。我还必须指出,此答案返回一个数组中的字符串。更完整的解决方案是parseFloat('0.' + (n + '').split('.')[1]) - totymedli
@cdmdotnet 的无位置限制解决方案在这里:https://dev59.com/mG855IYBdhLWcg3wJQvT#59469716 - user1742529
显示剩余4条评论

42

0.2999999999999998怎么能算是一个可接受的答案呢?如果我是提问者,我希望得到的答案是0.3。这里存在虚假精度的问题,我的使用floor、%等方法进行实验表明JavaScript喜欢在这些操作中保留虚假精度。因此,我认为将答案转换为字符串的方法是正确的。

我的做法是:

var decPart = (n+"").split(".")[1];

具体来说,我正在使用100233.1,我想要的答案是".1"。


9
我基本同意,但是你不能仅使用 '.' 作为正则表达式来匹配小数点,因为 小数点是一个国际化字符 - Marcel Stör
2
@jomofrodo 实际上,有些人可能希望得到非圆整的值。我不记得 OP 是否要求圆整的值,只是要分割值。 - VVV
1
@VVV 是的,有些人可能想要非圆整值。但仅仅因为你可能想要精确到小数点后9位并不意味着你的输入数据实际上支持它。这就是为什么它被称为“虚假精度”。如果你的输入是3.1,那么你的答案最多只能有十分位的精度,即0.1。如果你的答案是0.09,那么这意味着你实际上已经计算/测量到百分位的精度,而事实上原始输入只有十分位的精度。 - jomofrodo
1
@MarcelStör 这可以很容易地处理: var decPart = (n.toLocaleString("en")).split(".")[1]; - jem
3
.toString()方法不考虑国际化。根据MDN和ECMA规范,十进制分隔符始终是. - Andrewmat
显示剩余3条评论

39
这是我做的方法,我认为这是最直接的方式:
var x = 3.2;
var int_part = Math.trunc(x); // returns 3
var float_part = Number((x-int_part).toFixed(2)); // return 0.2

如果小数部分超过2位,则此方法无效。使用这种方法,x = 3.2将给出与x = 3.20499相同的结果。 - M -

27

一个简单的方法是:

var x = 3.2;
var decimals = x - Math.floor(x);
console.log(decimals); //Returns 0.20000000000000018

不幸的是,它不能返回确切的值。 不过,这很容易解决:

var x = 3.2;
var decimals = x - Math.floor(x);
console.log(decimals.toFixed(1)); //Returns 0.2

如果您不知道小数位数,可以使用此选项:

var x = 3.2;
var decimals = x - Math.floor(x);

var decimalPlaces = x.toString().split('.')[1].length;
decimals = decimals.toFixed(decimalPlaces);

console.log(decimals); //Returns 0.2


12

不依赖于任何标准JS函数:

var a = 3.2;
var fract = a * 10 % 10 /10; //0.2
var integr = a - fract; //3

请注意,此仅适用于带有一个小数点的数字。

3
你能解释一下为什么你认为这是与语言无关的吗?这是 JavaScript。 - hotzst
4
@hotzst,没有特定于语言的功能。 - Nurlan
3
因为这仅涉及纯数学,所以与语言无关。这是一个实用的解决方案。通过以下代码可以得到所需小数位数:var factor = Math.pow(10, desiredFractionLength); var fract = a * factor % factor / factor; - muratgozel

9
你可以使用 parseInt() 函数得到整数部分,然后用它来提取小数部分。
var myNumber = 3.2;
var integerPart = parseInt(myNumber);
var decimalPart = myNumber - integerPart;

或者你可以使用正则表达式,例如:

splitFloat = function(n){
   const regex = /(\d*)[.,]{1}(\d*)/;
   var m;

   if ((m = regex.exec(n.toString())) !== null) {
       return {
          integer:parseInt(m[1]),
          decimal:parseFloat(`0.${m[2]}`)
       }
   }
}

1
十进制部分为0.20000000000000018...这真的很难处理,因为0.2 < 0.20000000000000018返回true...3.2应该返回0.2 :P造成了这么多的不规则性,使用.toFixed(2)返回字符串 :P - Himanshu Bansal
@HimanshuBansal 这是一个JavaScript问题(这里有一个stackeoverflow问题)。您可以使用我建议的第二种方法。 - Sheki
我有一个略微不同的问题陈述...有点用了你们两种方法:P来解决它..^^ - Himanshu Bansal

6
无论十进制分隔符的区域设置如何,以下内容都适用...条件是仅使用一个字符作为分隔符。
var n = 2015.15;
var integer = Math.floor(n).toString();
var strungNumber = n.toString();
if (integer.length === strungNumber.length)
  return "0";
return strungNumber.substring(integer.length + 1);

它不太美观,但是它很准确。


当然,那是一个字符串,所以如果您想将其作为数字使用,您可能需要首先使用parseInt()。除非涉及到八进制而不是十进制数字,否则您不需要使用parseFloat()……这是我多年前隐约记得的一些事情。 - cdmdotnet

6
如果精度很重要且需要一致的结果,以下几个方法可以将任何数字的小数部分(包括前导的“0.”)返回为字符串。如果需要浮点数,请在末尾添加var f = parseFloat( result )
如果小数部分等于零,则返回"0.0"。空值、NaN和未定义的数字没有进行测试。

1. String.split

var nstring = (n + ""),
    narray  = nstring.split("."),
    result  = "0." + ( narray.length > 1 ? narray[1] : "0" );

2. String.substring, String.indexOf

var nstring = (n + ""),
    nindex  = nstring.indexOf("."),
    result  = "0." + (nindex > -1 ? nstring.substring(nindex + 1) : "0");

3. Math.floor, Number.toFixed, String.indexOf

var nstring = (n + ""),
    nindex  = nstring.indexOf("."),
    result  = ( nindex > -1 ? (n - Math.floor(n)).toFixed(nstring.length - nindex - 1) : "0.0");

4. Math.floor, Number.toFixed, String.split

var nstring = (n + ""),
    narray  = nstring.split("."),
    result  = (narray.length > 1 ? (n - Math.floor(n)).toFixed(narray[1].length) : "0.0");

这里有一个 jsPerf 链接:https://jsperf.com/decpart-of-number/ 我们可以看到,命题 #2 是最快的。

不要使用这些代码,一旦数字渲染切换到工程模式,它们就会出错。而且它们也不支持本地化。 - Spongman
你能解释一下什么是“数字渲染切换到工程模式”吗?此外,本地化并不相关,因为我们只想要一个数字的小数部分,而不是代表数字的本地化字符串。 - Gabriel Hautclocq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接