简体   繁体   English

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

[英]Converting a double to an int in Javascript without rounding

In C# the following code returns 2:在 C# 中,以下代码返回 2:

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

In Javascript, however, the only way of converting a "double" to an "int" that I'm aware of is by using Math.round/floor/toFixed etc. Is there a way of converting to an int in Javascript without rounding?然而,在 Javascript 中,我知道将“double”转换为“int”的唯一方法是使用 Math.round/floor/toFixed 等。有没有一种方法可以在 Javascript 中转换为 int 而无需舍入? I'm aware of the performance implications of Number() so I'd rather avoid converting it to a string if at all possible.我知道 Number() 的性能影响,所以我宁愿尽可能避免将其转换为字符串。

Use parseInt() .使用parseInt()

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

You can also use |您也可以使用| . .

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

I find the "parseInt" suggestions to be pretty curious, because "parseInt" operates on strings by design.我发现“parseInt”的建议非常奇怪,因为“parseInt”是按设计对字符串进行操作的。 That's why its name has the word "parse" in it.这就是为什么它的名字中有“解析”这个词。

A trick that avoids a function call entirely is完全避免函数调用的技巧是

var truncated = ~~number;

The double application of the "~" unary operator will leave you with a truncated version of a double-precision value. “~”一元运算符的双重应用将为您留下双精度值的截断版本。 However, the value is limited to 32 bit precision, as with all the other JavaScript operations that implicitly involve considering numbers to be integers (like array indexing and the bitwise operators).但是,该值被限制为 32 位精度,与所有其他隐含将数字视为整数的 JavaScript 操作(如数组索引和位运算符)一样。

edit — In an update quite a while later, another alternative to the ~~ trick is to bitwise-OR the value with zero:编辑——在很长一段时间后的更新中, ~~技巧的另一种替代方法是将值与零按位或:

var truncated = number|0;

Similar to C# casting to (int) with just using standard lib:与仅使用标准库的 C# 转换为(int)类似:

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

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

parseInt(d, 10);

There is no such thing as an int in Javascript. Javascript中没有int这样的东西。 All Numbers are actually doubles behind the scenes* so you can't rely on the type system to issue a rounding order for you as you can in C or C#.所有Numbers实际上都是幕后双打*,因此您不能像在 C 或 C# 中那样依赖类型系统为您发出舍入顺序。

You don't need to worry about precision issues (since doubles correctly represent any integer up to 2^53) but you really are stuck with using Math.floor (or other equivalent tricks) if you want to round to the nearest integer.您无需担心精度问题(因为双精度数正确表示高达 2^53 的任何整数),但如果您想四舍五入到最接近的整数,您确实会坚持使用 Math.floor(或其他等效技巧)。


*Most JS engines use native ints when they can but all in all JS numbers must still have double semantics. *大多数 JS 引擎尽可能使用原生整数,但所有 JS 编号仍然必须具有双重语义。

A trick to truncate that avoids a function call entirely is一个完全避免函数调用的截断技巧是

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

To round a floating-point number to the nearest integer, use the addition/subtraction trick.要将浮点数舍入到最接近的整数,请使用addition/subtraction技巧。 This works for numbers with absolute value < 2 ^ 51.这适用于绝对值 < 2 ^ 51 的数字。

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

Note:笔记:

Halfway values are rounded to the nearest even using "round half to even" as the tie-breaking rule.即使使用“四舍五入到偶数”作为平局规则,中间值也会四舍五入到最接近的值。 Thus, for example, +23.5 becomes +24, as does +24.5.因此,例如,+23.5 变为 +24,+24.5 也是如此。 This variant of the round-to-nearest mode is also called bankers' rounding .这种四舍五入模式的变体也称为银行家四舍五入

The magic number 6755399441055744.0 is explained in the stackoverflow post "A fast method to round a double to a 32-bit int explained" .幻数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))}`); });

As @Quentin and @Pointy pointed out in their comments, it's not a good idea to use parseInt() because it is designed to convert a string to an integer.正如@Quentin 和@Pointy 在他们的评论中指出的那样,使用parseInt()不是一个好主意,因为它旨在将字符串转换为整数。 When you pass a decimal number to it, it first converts the number to a string, then casts it to an integer.当您将十进制数传递给它时,它首先将数字转换为字符串,然后将其转换为整数。 I suggest you use Math.trunc() , Math.floor() , ~~num , ~~v , num | 0我建议你使用Math.trunc()Math.floor()~~num~~vnum | 0 num | 0 , num << 0 , or num >> 0 depending on your needs. num | 0num << 0num >> 0取决于您的需要。 This performance test demonstrates the difference in parseInt() and Math.floor() performance.此性能测试演示了parseInt()Math.floor()性能的差异。 Also, this post explains the difference between the proposed methods.此外,这篇文章解释了所提出的方法之间的区别。

那这个呢:

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

I think that the easiest solution is using the bitwise not operator twice:我认为最简单的解决方案是使用按位非运算符两次:

const myDouble = -66.7;
console.log(myDouble); //-66.7
const myInt = ~~myDouble;
console.log(myInt); //-66
const myInt = ~~-myDouble;
console.log(myInt); //66

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM