Converting a double to an int in Javascript without rounding
Asked Answered
N

9

90

In C# the following code returns 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? I'm aware of the performance implications of Number() so I'd rather avoid converting it to a string if at all possible.

Nichrome answered 5/12, 2011 at 16:27 Comment(4)
Why did you rule out Math.floor?Manipur
The answers advising you to use "parseInt()" may all convert to a string internally first, because that's what "parseInt()" expects. Really, either "Math.floor()" or else "~~num" (double "not" operation) will truncate your double-precision value to an integer.Paris
He probably rules out Math.floor because it behaves different for negative numbers. Compare Math.floor(-2.5) and -2.5|0.Confound
Discarding the fractional part is ALWAYS rounding, per definition. You probably want: rounding towards zero.Clementeclementi
B
206

Use parseInt().

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

You can also use |.

var num = 2.9
console.log(num | 0); // 2
Biforked answered 5/12, 2011 at 16:30 Comment(8)
May want to add a radix (10) as the second parameterBruno
parseInt(num, 10); -- you added it to the console.log call, not parseIntBruno
failure to add it would result in parseInt("09") returning 0Bruno
@AdamRackis: Not my day, argh! Changed once again. Thank you for being my eyes :).Biforked
The OR method seems to work perfectly, and doesn't rely on string conversionNichrome
TypeScript doesn't support passing a double value into parseInt, so I used the second option. Thanks!Electronegative
I would recommend strongly against using parseInt for converting a double to an int. parseInt expects a string argument and JS represents long double strings in scientific notation. Run parseInt(0.0000005); and see what the result is, you'll be shocked.Fondness
let n = 0x1_0000_0000 + 2.9; n is 4_294_967_298.9. As expected, parseInt(n) is 4_294_967_298. However, n|0 is 2! That's because, for bitwise operations, JS keeps only the low 32 bits and zeros out the higher bits. Being much faster, OR'ing is nevertheless to be preferred. But do beware of its limitations! And also be aware parseInt fails for small numbers where the string representation is scientific Isee cbender, above).Subassembly
P
63

I find the "parseInt" suggestions to be pretty curious, because "parseInt" operates on strings by design. 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).

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;
Paris answered 5/12, 2011 at 16:54 Comment(2)
A nice trick, but not very readable, so not recommended for shared codebases.Pucka
@ColinBasnett it's idiomatic (both ~~ and |0) in JavaScript, and certainly better than parseInt() which really makes no sense. JavaScript doesn't really have integers except in transient form in the middle of expressions involving binary operators.Paris
C
40

Similar to C# casting to (int) with just using standard lib:

Math.trunc(1.6) // 1
Math.trunc(-1.6) // -1
Clementeclementi answered 18/10, 2018 at 11:9 Comment(8)
I don't understand why it has so few upvotes, for somebody that doesn't do javascript everyday it seems to be the most straighforward and readable way to achieve this. I know if I try "| 0" or "~~" of other answers, I will never remember what it does and I'll be confused when I will see it next time. At least your solution is self explanatory. Thanks !Disquiet
@Disquiet agreed, few upvotes maybe because it was answered 7 years later :(Epigastrium
@Epigastrium Few upvotes? This is my top answer, and it is has risen to 3rd place in the list of 7 answers. Not bad at all :-)Clementeclementi
@Densmore As I appreciate your effort to edit my answer, I feel that the sense of simplicity got lost. I am considering Rollback. In my view, Run Code Snippet is useful for complex code where it is not obvious it works just by inspecting the code. Here it seems useless overkill. Also, why mention ES6 if OP already mentioned Math.Floor etc?Clementeclementi
@Clementeclementi Math.floor is available in JS since its very initial versions (ES1). trunc was added later, and if one wants compatibility with browsers like Internet Explorer, they surely cannot use trunc (unlike floor/round/~~/parseInt, they work on IE as well). Yeah, you can remove the snippet if you feel like simplicity is lost. :)Densmore
@Densmore Your comment on ES6 would be a great comment that I would be glad to upvoteClementeclementi
@Roland, relatively...I think this answer should be on 1st :)Epigastrium
@Epigastrium just wait for 39 others to agree with you and to vote me up and this answer will rise one step :-)Clementeclementi
S
9

Just use parseInt() and be sure to include the radix so you get predictable results:

parseInt(d, 10);
Sloop answered 5/12, 2011 at 16:29 Comment(0)
H
5

There is no such thing as an int in Javascript. 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#.

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.


*Most JS engines use native ints when they can but all in all JS numbers must still have double semantics.

Haematic answered 5/12, 2011 at 16:35 Comment(1)
All JS engines use native ints when they can (note that ranges differ: V8 notably special cases 31-bit ints). Even SpiderMonkey almost two decades ago used native ints when they can (when it was written, it was common for desktop computers to not have hardware floating-point support, so it was a very necessary performance optimization).Coaxial
K
2

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. This works for numbers with absolute value < 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. 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".

// 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))}`);  
});
Klotz answered 15/8, 2020 at 10:20 Comment(0)
P
2

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
Priest answered 11/5, 2022 at 11:20 Comment(0)
B
1

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. 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, num << 0, or num >> 0 depending on your needs. This performance test demonstrates the difference in parseInt() and Math.floor() performance. Also, this post explains the difference between the proposed methods.

Burrill answered 27/12, 2018 at 14:26 Comment(0)
Z
0

What about this:

if (stringToSearch.IndexOfAny( ".,;:?!".ToCharArray() ) == -1) { ... }
Zasuwa answered 15/7, 2021 at 19:1 Comment(1)
Please add more of an explanation. How does the very very small peice of code help the OP with their problem? There are 7 other well-recieved solutions to this question, if none of those solutions help you, you may ask another question.Erector

© 2022 - 2024 — McMap. All rights reserved.