【问题标题】:Converting a double to an int in Javascript without rounding在Javascript中将double转换为int而不四舍五入
【发布时间】:2012-01-13 09:04:12
【问题描述】:

在 C# 中,以下代码返回 2:

double d = 2.9;
int i = (int)d;
Debug.WriteLine(i);

然而,在 Javascript 中,我知道将“double”转换为“int”的唯一方法是使用 Math.round/floor/toFixed 等。有没有一种方法可以转换为 int Javascript没有四舍五入?我知道 Number() 的性能影响,所以我宁愿尽可能避免将其转换为字符串。

【问题讨论】:

  • 为什么排除Math.floor
  • 建议您使用“parseInt()”的答案可能都首先在内部转换为字符串,因为这是“parseInt()”所期望的。真的,“Math.floor()”或“~~num”(双“非”操作)会将您的双精度值截断为整数。
  • 他可能排除了Math.floor,因为它对负数的行为不同。比较Math.floor(-2.5)-2.5|0
  • 丢弃小数部分总是四舍五入,根据定义。你可能想要:rounding towards zero.

标签: javascript casting floating-point int


【解决方案1】:

使用parseInt()

var num = 2.9
console.log(parseInt(num, 10)); // 2

您也可以使用|

var num = 2.9
console.log(num | 0); // 2

【讨论】:

  • 可能要添加一个基数 (10) 作为第二个参数
  • parseInt(num, 10); -- 你将它添加到 console.log 调用中,而不是 parseInt
  • 添加失败会导致 parseInt("09") 返回 0
  • @AdamRackis:不是我的日子,啊!又变了一次。谢谢你成为我的眼睛:)。
  • OR 方法似乎可以完美运行,并且不依赖字符串转换
【解决方案2】:

我发现“parseInt”的建议非常奇怪,因为“parseInt”在设计上对 strings 进行操作。这就是为什么它的名字里有“parse”这个词。

一个完全避免函数调用的技巧是

var truncated = ~~number;

“~”一元运算符的双重应用将为您提供双精度值的截断版本。但是,该值被限制为 32 位精度,与所有其他隐含将数字视为整数的 JavaScript 操作(如数组索引和位运算符)一样。

edit — 在不久之后的更新中,~~ 技巧的另一种替代方法是将值与零按位或:

var truncated = number|0;

【讨论】:

  • 一个不错的技巧,但可读性不强,因此不推荐用于共享代码库。
  • @ColinBasnett 它在 JavaScript 中是惯用的(~~|0),当然比 parseInt() 更好,这真的没有意义。 JavaScript 实际上并没有整数,除了在涉及二元运算符的表达式中间的瞬态形式。
【解决方案3】:

类似于 C# 强制转换为 (int),仅使用标准库:

Math.trunc(1.6) // 1
Math.trunc(-1.6) // -1

【讨论】:

  • 我不明白为什么它有这么少的赞成票,对于不每天使用 javascript 的人来说,这似乎是实现这一目标的最直接和可读的方式。我知道如果我尝试其他答案的“| 0”或“~~”,我永远不会记得它做了什么,下次看到它时我会感到困惑。至少您的解决方案是不言自明的。谢谢!
  • @AFract 同意,很少有人赞成,可能是因为它在 7 年后得到了回答:(
  • @Loki 很少有人支持?这是我的最佳答案,在 7 个答案列表中已上升到第三位。一点也不差:-)
  • @Roland Math.floor 从最初的版本 (ES1) 开始在 JS 中可用。 trunc 是后来添加的,如果想要与 Internet Explorer 等浏览器兼容,他们肯定不能使用 trunc(与 floor/round/~~/parseInt 不同,它们也适用于 IE)。是的,如果您觉得失去了简单性,您可以删除 sn-p。 :)
  • @Roland,相对来说......我认为这个答案应该是第一个 :)
【解决方案4】:

只需使用 parseInt() 并确保包含基数,以便获得可预测的结果:

parseInt(d, 10);

【讨论】:

    【解决方案5】:

    在 Javascript 中没有 int 这样的东西。所有Numbers 实际上都是幕后双打*,因此您不能像在 C 或 C# 中那样依赖类型系统为您发出舍入顺序。

    您无需担心精度问题(因为双精度数正确表示最大为 2^53 的任何整数),但如果您想四舍五入到最接近的值,您确实无法使用 Math.floor(或其他等效技巧)整数。


    *大多数 JS 引擎在可能的情况下使用原生整数,但所有 JS 数字仍然必须具有双重语义。

    【讨论】:

    • 所有 JS 引擎都尽可能使用原生整数(请注意范围不同:V8 尤其是特殊情况 31 位整数)。甚至在大约 20 年前,SpiderMonkey 也尽可能使用原生整数(在编写它时,台式机通常不支持硬件浮点,因此这是非常必要的性能优化)。
    【解决方案6】:

    一个完全避免函数调用的截断技巧是

    var number = 2.9
    var truncated = number - number % 1;
    console.log(truncated); // 2 
    

    要将浮点数四舍五入到最接近的整数,请使用addition/subtraction 技巧。这适用于绝对值

    var number = 2.9
    var rounded = number + 6755399441055744.0 - 6755399441055744.0;  // (2^52 + 2^51)
    console.log(rounded); // 3 
    

    注意:

    即使使用"round half to even" 作为平局规则,中间值也会四舍五入到最接近的值。因此,例如,+23.5 变为 +24,+24.5 也是如此。这种四舍五入模式的变体也称为银行家四舍五入

    幻数6755399441055744.0 在stackoverflow 帖子"A fast method to round a double to a 32-bit int explained" 中进行了解释。

    // Round to whole integers using arithmetic operators
    let trunc = (v) => v - v % 1;
    let ceil  = (v) => trunc(v % 1 > 0 ? v + 1 : v);
    let floor = (v) => trunc(v % 1 < 0 ? v - 1 : v);
    let round = (v) => trunc(v < 0 ? v - 0.5 : v + 0.5);
    
    let roundHalfEven = (v) => v + 6755399441055744.0 - 6755399441055744.0; // (2^52 + 2^51)
    
    console.log("number  floor   ceil  round  trunc");
    var array = [1.5, 1.4, 1.0, -1.0, -1.4, -1.5];
    array.forEach(x => {
        let f = x => (x).toString().padStart(6," ");
        console.log(`${f(x)} ${f(floor(x))} ${f(ceil(x))} ${f(round(x))} ${f(trunc(x))}`);  
    });

    【讨论】:

      【解决方案7】:

      正如@Quentin 和@Pointy 在他们的cmets 中指出的那样,使用parseInt() 并不是一个好主意,因为它旨在将字符串转换为整数。当您将十进制数传递给它时,它首先将数字转换为字符串,然后将其转换为整数。我建议您根据需要使用Math.trunc()Math.floor()~~num~~vnum | 0num &lt;&lt; 0num &gt;&gt; 0This performance test 展示了 parseInt()Math.floor() 性能的差异。 此外,this post 解释了建议方法之间的区别。

      【讨论】:

        【解决方案8】:

        这个呢:

        if (stringToSearch.IndexOfAny( ".,;:?!".ToCharArray() ) == -1) { ... }
        

        【讨论】:

        • 请添加更多解释。非常非常小的代码片段如何帮助 OP 解决他们的问题?此问题还有其他 7 个广受好评的解决方案,如果这些解决方案都没有帮助您,您可以提出另一个问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-08
        • 1970-01-01
        • 1970-01-01
        • 2014-06-02
        • 2015-04-10
        • 2012-05-04
        • 1970-01-01
        相关资源
        最近更新 更多