在Javascript中将double转换为int而不四舍五入

Posted

技术标签:

【中文标题】在Javascript中将double转换为int而不四舍五入【英文标题】:Converting a double to an int in Javascript without rounding 【发布时间】: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. 【参考方案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 在*** 帖子"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; 0。 This performance test 展示了 parseInt()Math.floor() 性能的差异。 此外,this post 解释了建议方法之间的区别。

【讨论】:

【参考方案8】:

这个呢:

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

【讨论】:

请添加更多解释。非常非常小的代码片段如何帮助 OP 解决他们的问题?此问题还有其他 7 个广受好评的解决方案,如果这些解决方案都没有帮助您,您可以提出另一个问题。

以上是关于在Javascript中将double转换为int而不四舍五入的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中将 double 转换为 int

如何在 Swift 中将数据转换为 Doubles、Ints 和 Strings 等类型?

在 Python 3 中将字符串转换为 int 或 float?

如何在 Java 中将 Integer[] 转换为 int[] 数组?

为啥不能使用 SqlFunctions 在 LinQ 中将 int 转换为字符串?

java中将一个double类型的数强制转换为long 型是四舍五入吗?