在Javascript中将双精度型转换为整型,不需要舍入

Converting a double to an int in Javascript without rounding

本文关键字:整型 不需要 舍入 转换 Javascript 双精度型      更新时间:2023-09-26

在c#中,下面的代码返回2:

double d = 2.9;
int i = (int)d;
Debug.WriteLine(i);
然而,在Javascript中,我所知道的将"double"转换为"int"的唯一方法是使用Math。轮/地面/toFixed等等。有没有一种方法转换成int在Javascript没有四舍五入?我知道Number()的性能影响,所以如果可能的话,我宁愿避免将其转换为字符串。

使用parseInt()

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

您也可以使用|

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

我发现"parseInt"的建议是相当奇怪的,因为"parseInt"操作字符串设计。这就是为什么它的名字中有"parse"这个词。

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

var truncated = ~~number;

"~"一元操作符的双重应用将为您留下双精度值的截断版本。然而,该值被限制为32位精度,因为所有其他JavaScript操作都隐含地将数字视为整数(如数组索引和按位操作符)。

编辑本;在相当长一段时间后的更新中,~~技巧的另一种替代方法是将值与零按位或:

var truncated = number|0;

类似于c#转换为(int),只是使用标准库:

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

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

parseInt(d, 10);

在Javascript中没有int这样的东西。所有的Numbers实际上都是在后台的double,所以你不能像在C或c#中那样依赖类型系统为你发出舍入命令。

你不需要担心精度问题(因为double正确地表示2^53以内的任何整数),但你真的要使用Math。如果你想四舍五入到最接近的整数


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

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

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

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

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

注意:

使用"四舍五入"将中间值四舍五入到最接近的偶数;作为决胜局规则。例如,+23.5变成+24,+24.5也变成+24。这种四舍五入模式的变体也称为银行家四舍五入

幻数6755399441055744.0在stackoverflow post中有解释;解释了一种将双精度浮点数舍入为32位整型的快速方法;

// 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))}`);  
});

正如@Quentin和@Pointy在他们的评论中指出的那样,使用parseInt()不是一个好主意,因为它被设计为将字符串转换为整数。当您向它传递一个十进制数字时,它首先将该数字转换为字符串,然后将其强制转换为整数。我建议您根据需要使用Math.trunc(), Math.floor(), ~~num, ~~v, num | 0, num << 0num >> 0。这个性能测试演示了parseInt()Math.floor()性能的差异。此外,这篇文章还解释了所提出的方法之间的区别。

我认为最简单的解决方案是使用两次按位not操作符:

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

这个呢:

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