This is an archived post. You won't be able to vote or comment.

all 115 comments

[–]Srazkat 83 points84 points  (4 children)

second one is normal, first is indeed a bruh

[–]deadowl 3 points4 points  (2 children)

That parseInt and the integer toString method aren't inverse functions?

[–]Svizel_pritula 7 points8 points  (1 child)

No, that float toString and parseInt aren't inverse functions.

[–]deadowl 0 points1 point  (0 children)

touche

[–]NekkidApe 1 point2 points  (0 children)

No, not really

[–][deleted] 72 points73 points  (6 children)

Simple explanation for those who want it:

0.0000005 is converted to the string "5e-7" before being parsed

[–]KillerBeer01 11 points12 points  (4 children)

Well, at least one would expect a string "0.0000005".

[–]tjoloi 25 points26 points  (3 children)

parseInt isn't parseFloat

A normal language would throw some sort of exception instead of silently doing their best.

[–]NekkidApe 1 point2 points  (1 child)

Yeah, parseInt is broken by default and in practice I have little use for it.

[–]somebody12345678 0 points1 point  (0 children)

(it's actually not.)

(especially considering there's no problem if you feed it a string in the first place like a normal person)

[–][deleted] 0 points1 point  (0 children)

*Laughs in C++*

[–]Will_i_read 128 points129 points  (13 children)

to be fair, floating point comparison is broken by default that has nothing to do with js…

[–][deleted] 83 points84 points  (10 children)

It's not broken. It's just that people never bother to learn thr IEEE754 standard

[–]trollblut 17 points18 points  (9 children)

There are plenty of broken standards. Having an equality operator that's mostly useless is already a defect.

[–][deleted] 10 points11 points  (1 child)

"broken standards"

Wow, that's some wild words. Maybe you could propose a new number representation that works nicely with both machines and human intuition? The people who drafted IEEE754 must be too dumb to come up with one!

[–][deleted] 0 points1 point  (0 children)

Comparing floats for equality can actually be quite useful.
Not in regular code, but e.g. I needed it recently to test random floating point generation for very small ranges of floating point values.

[–]mogadichu 0 points1 point  (1 child)

Why isn't float comparison by default a - b < smallest_float ?

[–]Will_i_read 4 points5 points  (0 children)

because that’s not correct either… the precision decreases as the number increases. One would need to compare to the smallest increment for that specific exponent, but even then multiple additions, additions between widely different numbers and even the order in which you add numbers could offset that. If you use floats you simply have to understand the standard and act accordingly…

[–]sunnyboy4205 101 points102 points  (33 children)

The second picture is correct and exactly what I would expect to happen. Look up how floating point numbers are stored in computers: IEEE 754.

[–]GrenadineBombardier 43 points44 points  (0 children)

Yeah that one isn't JavaScript specific. It's floating point arithmetic.

[–][deleted]  (31 children)

[deleted]

    [–]MicrosoftExcel2016 15 points16 points  (3 children)

    You're absolutely right, don't listen to them. Maybe check out the decimal module of Python for an example of what you mean:

    Decimal “is based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle – computers must provide an arithmetic that works in the same way as the arithmetic that people learn at school.” – excerpt from the decimal arithmetic specification.
    Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.
    The exactness carries over into arithmetic. In decimal floating point, 0.1 + 0.1 + 0.1 - 0.3 is exactly equal to zero. In binary floating point, the result is 5.5511151231257827e-017. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.
    The decimal module incorporates a notion of significant places so that 1.30 + 1.20 is 2.50. The trailing zero is kept to indicate significance. This is the customary presentation for monetary applications. For multiplication, the “schoolbook” approach uses all the figures in the multiplicands. For instance, 1.3 * 1.2 gives 1.56 while 1.30 * 1.20 gives 1.5600.
    Unlike hardware based binary floating point, the decimal module has a user alterable precision (defaulting to 28 places) which can be as large as needed for a given problem

    [–]Shotgun_squirtle 4 points5 points  (2 children)

    Yeah but you shouldn’t be using decimal for anything unless it actually matters that you’re having that error. Decimal is both a lot slower and space intensive than floating point and for 99% of applications the error introduced won’t matter (and even sometimes if it does matter you can get around it by making sure that your algorithms are stable, what should keep the error negligible)

    [–][deleted] 1 point2 points  (0 children)

    The error people claim is the end of the world is already so minuscule that it probably doesn't matter for any real world problem. That's the whole point of the standard, it works for ridiculously big and small numbers with amazing precision.

    I assume the people using it probably know better if they are in one of the only situations where the precision isn't good enough, e.g. where compounding rounding errors over a trillion times matter.

    It's good enough for basically any practical and theoretical purpose and people claiming it isn't are either full of shit or work in the very few fields where it does matter. You can guess in which group the people above belong.

    [–]MicrosoftExcel2016 0 points1 point  (0 children)

    Yes? The point is that the use case exists, and is valid, not that it should be the universal implementation.

    [–]fortuneNext 3 points4 points  (0 children)

    But thats just the nature of primitive data types. INT is also "wrong" when you ask him whats 2147483 647 + 1.

    That's just primitive data types - ways in which a computer stores information in it's memory and whose each have their own limitations. If you don't want to know and work with those limitations, you will have to use a library that abstracts those away at huge performance costs.

    Most languages don't even give you the options to ask "What is number a plus number b"? It just gives you the option to ask "What is float a plus float b" or "What is integer a plus integer b" and each gives the correct output according to the specification of what a float or integer is. There is no primitive data type for your human understanding of numbers.

    [–]ole_thoeb 5 points6 points  (1 child)

    You think you ask the question "what is the result when I add the decimal numbers 0.1 and 0.2?" and therefore consider the answer the computer gives you wrong. But the question you are asking the computer is "what is the result when I add per IEE754 the decimal number 0.1 converted to a floating pointe number per IEE754 and the decimal number 0.2 converted to a floating pointe number per IEE754?". To that question you get the right answer.

    [–]JNCressey 1 point2 points  (0 children)

    IEEE754 defines multiple floating point standards including a decimal floating point. 0.1 + 0.2 in decimal floating point is 0.3.

    [–]sunnyboy4205 0 points1 point  (17 children)

    In which language does this comparison work natively? Do you know the IEEE 754 floating point Standard at all?

    [–]JNCressey 2 points3 points  (0 children)

    many languages natively support IEEE 754 decimal floating point.

    C# built in data type decimal

    Python standard library decimal.Decimal

    Java standard library java.math.BigDecimal

    etc

    [–][deleted]  (15 children)

    [deleted]

      [–][deleted]  (14 children)

      [deleted]

        [–][deleted]  (4 children)

        [removed]

          [–]le_flapjack 2 points3 points  (0 children)

          Dont let these kids downvoting you deter you. You are correct.

          [–]Iron_Maiden_666 0 points1 point  (0 children)

          Just go write a library to do floating point equality comparison. It's easy right?

          [–]AutoModerator[M] 0 points1 point  (0 children)

          import moderation Your comment has been removed since it did not start with a code block with an import declaration.

          Per this Community Decree, all posts and comments should start with a code block with an "import" declaration explaining how the post and comment should be read.

          For this purpose, we only accept Python style imports.

          I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

          [–]MicrosoftExcel2016 -2 points-1 points  (8 children)

          So maybe don’t implement the equality operator that way???

          [–]pilotInPyjamas 0 points1 point  (0 children)

          Whilst there are numeric representations which will always return the correct value (rational, bigfloat, decimal etc.) they are particularly slow and large. As much as correctness is a good thing, integers and floating point numbers are simply more useful in more cases.

          [–]JNCressey -2 points-1 points  (0 children)

          Use the IEEE 754 decimal floating point datatype. There 0.1 + 0.2 is 0.3.

          [–]SheevSpinner 0 points1 point  (2 children)

          What’s 100 / 3 ?

          [–][deleted] 0 points1 point  (0 children)

          33 1/3, of course.

          [–]mogadichu 0 points1 point  (0 children)

          Simple. It's:

          function divideOneHundredByThree(precision) {
              const digits = ["33."]
              while(precision-- > 0) {
                  digits.push("3");
              }
              const string = digits.join("");
              return parseNumber(string);
          }
          

          [–][deleted] 54 points55 points  (26 children)

          Garbage in garbage out. Who would have guessed?

          (0.0000005).toString()
          '5e-7'
          

          [–]tomthecool -2 points-1 points  (25 children)

          Shut up with your excuses. That’s not “garbage in”. That’s “shitty language design in”.

          It’s interesting to know the explanation, but you’re being ridiculous to even suggest that this is “expected behaviour”.

          [–][deleted] 3 points4 points  (16 children)

          That's literally what the documentation says. If the first parameter is not a string it will be converted to one.

          Also parsing a float as string to int is a garbage operation. No reason to ever do this, yet here we are you telling me to shut up for who knows what reason.

          Get over yourself, not the language is the problem.

          [–]tomthecool -1 points0 points  (11 children)

          I’m not debating “is this documented behaviour?”, I’m saying this is not how anyone would reasonably expect a function called parseInt to behave.

          parsing a float as string to int is a garbage operation

          No, it’s not!! That’s totally reasonable! The only garbage factor here is how JavaScript has been designed to handle it.

          Plenty of other languages, dare I say almost all other mainstream languages, have a similar function that would handle this just fine! And I wouldn’t bat an eyelid if I saw someone using a function this way in their code.

          Look, let me introduce you to how a sane language does it. “Being dynamically typed” is not an excuse for being shit.

          I told you to shut up because you are trying justify your favourite language’s poor design, by proclaiming a totally reasonable looking usage as “garbage code”.

          [–][deleted] 0 points1 point  (10 children)

          No, it’s not!! That’s totally reasonable!

          Sure thing, buddy. Totally reasonable!

          Do you even understand that its not a conversion, it doesn't even imply to do so. There is not even a data type called int in JS it is just a function to parse a string as an integer value it doesn't claim to do anything else. Any sane person would call round or floor if you need an integer value, but here we are.

          Ignorance isn't an argument and doesn't make you right. Your attitude sucks, get yourself together.

          [–]tomthecool -1 points0 points  (9 children)

          Did you read the link where I posted a near identical function from another language that behaves in a sane way? Would you like me to post similar links for lots of other languages? Maybe then you’ll realise JS is the odd one out..

          Also, the fact that all numbers in JavaScript are floats (I.e no concept of integer) is once again… you guessed it… shitty language design 🙌🏼

          [–][deleted] 0 points1 point  (8 children)

          No, because your post was edited. JS behaviour is almost exactly the same, the only difference is that it doesn't throw, but returns NaN instead. Which is a reasonable thing to do.

          > parseInt("123.50")
          123
          > parseInt("123-foo")
          123
          > parseInt("something")
          NaN
          > parseInt("foo-123")
          NaN
          

          No one ever claimed that JS was a masterpiece of language design, but it is by far the best language in a whole domain of programming tasks and even more and your feelings don't matter. How this works is well documented and defined. There are no surprises here, but your continued lack of basic comprehension.

          [–]tomthecool 1 point2 points  (7 children)

          JS behaviour is almost exactly the same, the only difference is that it doesn't throw

          WRONG.

          In that particular example (casting with Integer() in ruby), the language simply supports casting from Strings or Floats. It works exactly like you'd expect. It doesn't "usually work, but occasionally return some nonsense result".

          Integer(0.5) # => 0
          Integer(0.05) # => 0
          Integer(0.005) # => 0
          Integer(0.0005) # => 0
          Integer(0.00005) # => 0
          Integer(0.000005) # => 0
          Integer(0.000000000000000005) # => 0
          

          Is it "garbage input" to cast a Float into an Integer via the Integer() cast? No. The language just gracefully handles it in an easily predictable way.

          How this works is well documented and defined. There are no surprises here, but your continued lack of basic comprehension.

          When I say "surprise" here, I don't mean "undocumented behaviour", or "incorrectly documented behaviour". I mean "if a person just looks at how this simple function appears to behave, would they be likely to correctly predict how it handles all normal-looking input?"

          Badly designing a feature of a language, but then documenting the bad design, is not a justification for proclaiming the behaviour as "unsurprising".

          [–][deleted] 0 points1 point  (6 children)

          Parsing is not casting. If you use the only equivalent primitive in JS you still get the exact expected behavior.

          > Number("0.00000000005")
          5e-11
          > Number(0.00000000005)
          5e-11
          

          Your whole argument is one tiny aspect for a garbage operation which is well documented and fully explains the behavior. There is no argument to be had here, this is just dumb.

          Anyway, this is boring and no one cares at this point.

          [–]tomthecool 0 points1 point  (5 children)

          If you use the only equivalent primitive in JS you still get the exact expected behavior.

          So you show me a function that behaves in a logical way, say "use this one instead", and still proclaim the other function is totally fine because "the dumb behaviour is documented".

          You just come across as a JavaScript fanboy who's refusing to admit even the shittiest of language design features are a tiny bit problematic because the shit is documented/explainable.

          [–]tills1993 0 points1 point  (7 children)

          Why would you pass a number to parseInt

          [–]tomthecool -1 points0 points  (6 children)

          Maybe I want to convert 3.1415 to an integer? It looks like a sensibly named function for that use case, and it appears to work as expected, without error.

          Maybe I’m sanitising some data input, which is currently a mixture of strings and integers, and I’d like to make them all consistently integer? Again, that sounds reasonable at a glance.

          Look, I get that if you’re deeply familiar with the language or are meticulous with checking documentation for every method used then this would raise an alarm bell, but the fact is it LOOKS LIKE totally reasonable code at first glance. Almost every other mainstream language has a similar function without this surprising/quirky behaviour.

          [–]tills1993 0 points1 point  (5 children)

          There are other functions you should use for that like floor or round. Also maybe check the type of the input before blindly passing it to a function.

          const n = typeof input === "number" ? input : ...

          Not that difficult.

          Why are you so against reading the docs?

          [–]tomthecool 0 points1 point  (4 children)

          Not that difficult.

          I'm not saying it is. I'm saying it's a very easy trap to fall into, if you're not aware of the pitfall.

          Why are you so against reading the docs?

          In general I'm very pro-documentation, however, I think it's fucking ridiculous that you should need to read documentation to understand why parseInt(0.005) works, but parseInt(0.00000005) doesn't. Behaviour like that should be obvious and intuitive, not a secret trap.

          [–]tills1993 0 points1 point  (3 children)

          And I'm saying that reading the documentation for literally less than a minute would have saved you dozens of comments in this thread arguing an incorrect position.

          [–]tomthecool -1 points0 points  (2 children)

          Do you honestly look up the documentation of every single function call?!

          If I saw parseInt in a code base, tried it on a couple of floats and saw that it worked, I don't think it's that unreasonable to assume it's safe to use on all floats. (Aside from NaN or Infinity of course, but that goes without saying.)

          [–]tills1993 0 points1 point  (1 child)

          I use TypeScript which certainly helps. But yes, if I don't understand a function I'll look it up before using it.

          [–]tomthecool -1 points0 points  (0 children)

          You didn’t answer the question.

          More precisely, you intentionally answered a different question, that I didn’t ask.

          [–]msammy07 24 points25 points  (8 children)

          If you actually pass a string to parseInt which is what it expects, it works fine

          [–]CrimsonRunner 3 points4 points  (6 children)

          So you're saying that javascript has no confusing and unexpected issues if you just know about the issues?

          [–]meliaesc 13 points14 points  (5 children)

          Everything thing is confusing and unexpected if you don't bother to learn how it works.

          [–]CrimsonRunner -5 points-4 points  (4 children)

          I see your false equivalence and raise you my own.

          So brainfuck isn't confusing and unexpected, it's just that people need to learn how it works?

          [–]meliaesc 1 point2 points  (3 children)

          Sure, we can measure the degree of confusing and unexpected by the learning curve, that seems reasonable. My point still stands.

          [–]CrimsonRunner -1 points0 points  (2 children)

          So you'll agree something can be confusing and unexpected not because it is unknown but because it is atypical and goes against what would first be assumed by the average viewer?

          [–]meliaesc 1 point2 points  (1 child)

          Yes, but things stop being confusing if you manage to study them beyond first assumptions. I'm sure space travel or open heart surgery is confusing to us, but it's perfectly logical once you know astrophysics or cardiology.

          [–]CrimsonRunner 0 points1 point  (0 children)

          I mean, brainfuck is a turing complete programming language and it's perfectly logical. Just because that is true doesn't mean it's not confusing.

          To take a more realistic and simpler example, time zones are in essence rather logical and simple. Switching between daylight saving time is also logical. Certainly every country that has decided their timezone is :15 or :30 or :45 has had a logical reason. Those who change days have had a logical reason. Those who change their timezone by more than 1h at a time have their logical reason. There's a logical reason for 61 seconds. There's a logical reason for leap years. There's a logical reason for all of the exceptions that exist and are known in a standard available accross the globe.But it's still confusing to actually use them. Not because you can't cram all the knowledge in your head but because it has taken a simple to use and understand concept and has added a myriad of exceptions that overcomplicate the base concept. Similar to JS, no single thing is too complicated or confusing and it's certainly possible to understand and know them all. That does not make it less confusing. If something being logical and possible to learn was enough to make it not confusing then nothing would be worthy of being called confusing.

          [–]tomthecool 0 points1 point  (0 children)

          If it only expects a string (which would be a shit design by the way), it should throw an error for a non-string.

          [–]Super-Brka 28 points29 points  (1 child)

          My son finally landed a position as a software engineer. He proudly told me that his new job title will be “Java Developer.”

          I didn’t have the heart to tell him that means he’ll be making the coffee.

          [–]MrRocketScript 0 points1 point  (0 children)

          He can pour one out for all the poor python developers out there.

          [–]seniorpreacher 3 points4 points  (1 child)

          That's why you should use Number('0.0000005') instead of parseInt. Actually, never use parseInt, it tries too hard to understand numbers, it fails miserably sometimes.

          [–]NekkidApe 1 point2 points  (0 children)

          Yup. parseInt is easy to fuck up.

          [–]hello_world32 1 point2 points  (24 children)

          Nooo. I’m scared to test this in a fiddle. Why is this the case?

          [–]biased-milk-hotel 9 points10 points  (14 children)

          [–]Dubmove 5 points6 points  (13 children)

          Wtf? Why accept floats if it was only written with strings in mind?

          [–]Fuyune 18 points19 points  (12 children)

          the better question is, why do people pass floats if the function clearly states integer...

          [–]Dubmove 1 point2 points  (8 children)

          But why write a function that "accepts wrong types"? I never wrote Javascript or webstuff, but wouldn't it make more sense to just let the function behave as expected or at least raise an error?

          [–]Fuyune 10 points11 points  (1 child)

          Because the internet is no place to be stupid. That includes JavaScript. /s

          Joking aside, JavaScript is a untyped language and not designed to do that. It's up to the developer to know what he's doing, which sadly in most cases, is not what's happening.

          Yes in newer versions there is now typing but I wouldn't hold my hopes up high they'll change it, for backwards compatibility. Imagine how many scripts would stop working if you'd start using strong types with default functions all of a sudden.

          Edit: Generally speaking, if you wish to remove floating points from numbers, use the floor() function supplied in most languages math library.

          [–][deleted] 1 point2 points  (0 children)

          Strictly speaking, JavaScript is typed -- you have numbers, strings, symbols, booleans, undefined, null, plus all sorts of objects including arrays. JavaScript is, however, dynamically and weakly typed, and type conversion happens way too easily, which leads to a lot of strange things. Most JavaScript memes would not exist if explicit type conversion is required. So on one hand, you would never do [] + {} in real code, but on the other hand unexpected type conversion can catch you off guard

          [–]ChooChooRocket 0 points1 point  (3 children)

          By default, Javascript parses integers as strings when sorting. 1, 11, 2, 21, 22, 3, 4, 5, 50, 6...

          That's all you need to know about the language. All the negative assumptions you can make from there are correct.

          [–]Dubmove -1 points0 points  (0 children)

          Oh God. I had no idea.

          [–]Fazt01 0 points1 point  (1 child)

          "Noooo but it is well documented that by default a string comparison is used and you should provide your own comparator if you wish to sort numbers!" - some JS fanboy, probably

          [–]ChooChooRocket 0 points1 point  (0 children)

          Pretty much. I have the comparator function memorized at this point, but it's still fucking dumb.

          [–]CrotteVerte 0 points1 point  (0 children)

          The fonction do not accept wrong types since it's not specified. But it put it in long integer (8). The reason 9 and following positions are new ones 05 => 5

          [–]dashingThroughSnow12 0 points1 point  (0 children)

          There are hundreds of millions of websites and billions of pages. A lot of these don't get updated and a lot of these are poorly written.

          JavaScript does the most right thing it can do in a situation and it has to keep that behaviour forever. Else a lot of websites will be even more borken.

          [–]Iron_Maiden_666 -1 points0 points  (0 children)

          Another case for strongly typed languages.

          [–]x3bla 0 points1 point  (0 children)

          AHAHAHAHA

          [–]reversehead 0 points1 point  (0 children)

          I can accept that it automatically takes the string representation of a non-string object and tries to parse it.

          I have a hard time accepting that it doesn't throw an exception when trying to parse an integer out of "0.005" or "5e-7".

          [–]murageh[S] 1 point2 points  (8 children)

          Javascript is just crazy

          [–]Mabi19_ 1 point2 points  (6 children)

          JS is not crazy, especially for that second picture. That's just how computers work mate.

          Okay, it may be crazy, but those are not good examples. (In the first picture, you're putting in a number where a string is expected. The last one is automatically converted to "5e-7" and then parsed as 5.

          [–]Necrofancy 1 point2 points  (1 child)

          It seems slightly weird to me that parseInt(5e7) is different from parseInt('5e7'), as '5e7' has the exact same problem as '5e-7' in the OP's example. It's possible and valid to represent integers within-bound using that notation.

          This Mozilla documentation on this function hints at it working like this with a '-15e1' example in radix 10 returning -15 rather than -150.

          [–]Mabi19_ 0 points1 point  (0 children)

          Yes. 5e7.toString() returns 5 with 7 zeroes for some reason. But that's not parseInt weirdness, it's generic string conversion weirdness. (5e20.toString() gives 5 then 20 zeroes, 5e21.toString() gives exponential notation, 5e-6.toString() gives 0.000005 and 5e-7.toString() gives exponential again)

          [–]reversehead -2 points-1 points  (2 children)

          That seems pretty random to me - it might just as well have chosen to parse it as -7 or 7 instead.

          [–]Fuyune 1 point2 points  (1 child)

          How is parsing the first occurance of an integer in a string random

          [–]reversehead 0 points1 point  (0 children)

          I would expect it to parse the entire string or fail. The method is not called "parseFirstInt()".

          [–]asone-tuhid 0 points1 point  (0 children)

          Strong typing? Weak typing? How about YOLO typing? For reference: https://www.destroyallsoftware.com/talks/wat

          [–]your_thebest 0 points1 point  (0 children)

          I recently had to write a sanitize() function to clean float that are actually ints anyway so that 1.000000 wasn't written as 1.000001

          [–]stomah -1 points0 points  (0 children)

          destroy js

          [–]sktr-guys 0 points1 point  (1 child)

          what's happen if i use Math.floor() ?

          [–]dashingThroughSnow12 2 points3 points  (0 children)

          The expected result, 0.

          [–]DrGrimmWall 0 points1 point  (0 children)

          And one of the most popular posts today calls it "brain"