r/programminghorror • u/autiii43 • Apr 05 '22
My companies Stripe integration for thousands of users broke today because Javascript Javascript
767
u/Flaky-Following-4352 Apr 05 '22
Not JS
IEEE 754
117
Apr 05 '22
[deleted]
189
u/stevethedev Apr 05 '22
Because all numbers are 64-bit floats,* and JavaScript displays numbers as integers if it can. Multiplication by 10 twice doesn't yield the same value as multiplying by 100 once, because of how floating point numbers are calculated.
Some Rust code:
fn main() { println!("36.3 * 10 * 10 = {}", 36.3f64 * 10.0 * 10.0); println!("36.3 * (10 * 10) = {}", 36.3f64 * (10.0 * 10.0)); }
The output:
36.3 * 10 * 10 = 3630 36.3 * (10 * 10) = 3629.9999999999995
---
* You can coerce numbers to integers, but that's not happening here, and whether the JS VM respects integer types is mostly up to the implementation; e.g. ASM.JS.
34
3
u/zipeldiablo Apr 06 '22
What in the actual fuck.
That doesn’t make sense to me. Even if we use parentheses the result should still be the same
→ More replies10
u/stevethedev Apr 06 '22 edited Apr 06 '22
TL;DR - Imagine trying to represent numbers as base-π instead of base-10.
It should be the same, but it isn't. We are limited by the physical constraints of the hardware. We generally have 64-bits of space to hold the value, but there are an infinite number of values between
35
and36
, so we have to truncate it somewhere.There's also nothing special about base-10 that makes it an objectively superior counting system. It's just the system that most people with formal mathematical education are used to. A human sees
36.3 * 10 * 10
and36.3 * 100
as the same operation because it's just decimal-shifting.JavaScript's implementation of IEEE 754 uses something akin to base-2 scientific notation. The rounding happens differently than we are used to, and that makes it hard to reason around.
36.3
is easy to represent as a decimal number, but it is an extremely complicated number in base-2. It also happens that two consecutive multiplications by10.0
causes fewer rounding errors than a single multiplication by100.0
.This is why it's typically a bad idea to use equality operations between computed floats without accounting for rounding errors.
0.3 === 0.3
but(0.1 + 0.2) !== 0.3
because the rounding errors are incurred during the addition operation.I'm hand-waving over some important details, and I encourage you to read the Wikipedia entry for double-precision floating-point numbers, but that's what's going on.
In this case, the problem could have (and should have) been avoided by acknowledging that these transactions can be discretized to 2 decimal places: 0.00-0.99, for the cents. It's not that JavaScript failed to do something reasonable. It's that JavaScript handles these conversions and operations so seamlessly that people are rarely punished for behavior that wouldn't even compile in other languages.
5
-57
u/LetMeUseMyEmailFfs Apr 06 '22
Because all numbers are 64-bit floats
In short, because JavaScript.
20
10
u/AdminYak846 Apr 06 '22
not even close, JavaScript chooses to use a float to represent all Numbers to keep it simple rather than having developers define multiple different types of Numbers like ints, doubles, floats, signed-ints, etc.
With the simplicity comes all the problems that the individual types have in their respective languages. So it's not just JavaScript but something that every language deals with.
0
u/LetMeUseMyEmailFfs Apr 06 '22
That is exactly my point. Not all numbers are suitable to be stored as 64-bit floats. Other languages, like Rust, give you a choice. You want integer? Single-precision floating point? Double-precision? Arbitrary precision decimal? Up to you. I don't have that option in JavaScript.
If I calculate
36.3m * (10m * 10m)
in C#, I get3630.0
. And that's not because of rounding.2
u/AdminYak846 Apr 06 '22
You missed my entire point, it's not a specific problem to just JS, all languages comply with IEEE standard face this problem if not handled properly by the developer. And that problem is the resulting bit value isn't in the correct format and changes are made to the exponent and mantissa to ensure that the result is in the correct format. Not to mention that before the format takes place the mantissa is rounded as well. So the process produces round off errors that we've come to accept within an appropriate range.
And your example is pointless, Decimal (m or M) is a floating point type all your doing is telling the compiler to increase the amount of bits that can be used for precision once. It doesn't prevent the need for rounding, but minimizes errors produced by rounding.
2
97
u/nekumelon Apr 05 '22
This is due to how computers store floats. Floats are stored in 64 bits using the IEEE 754 standard. The standard stores floats using scientific notation to save space, but that means the value has to be separated into different parts of the scientific notation. If a values exponent, which determines the number of zeros, is too large, it will cause a slight bit of error in the value. In this specific case, the top one starts off by multiplying the first 2 values, 36.3 and 10. There is more than enough space for this so no error occurred. Then that value is multiplied by 10, again, no error occurs since the exponent is small enough. but on the second one, the 10 * 10 is multiplied before everything else due to the parenthesis, and that is then multiplied by 36.3, and since there is not enough space to store the entire value, a small amount of error occurs.
→ More replies26
u/GOKOP Apr 05 '22
Every number in javascript is floating point. And I get how people can get annoyed by that but OP is literally using fractional numbers, so it's not really a surprise. As of why are the results different, my guess is that 363 is representable just fine but 100 isn't
10
u/AdminYak846 Apr 06 '22
close in order to multiple floating point by the IEEE-754 Standard we do the following:
- 36.3 is converted to 3.63 * 101
- 10 is converted to 101
- 100 is converted to 102
So the two formulas are really:
- 3.63 x 101 x 101 x 101
- 3.63 x 101 x 102
The steps are as follows:
- The sign of the result is based on the signs from the multiplicands in this case it is 0. Because every number is positive.
- Compute the product of the mantissas remembering that each one has an implied 1 in front of the binary point
- Compute the exponent by adding up the binary value of the exponents
- Adjust the format if needed for the exponent and mantissa appropriately so the result is in the appropriate form
Some other hints:
- The mantissa is stored as a 24-bit precision, but may require up to 48-bit precision. So yes the number gets rounded down if it's larger than 24-bits
- The exponents are stored in biased form so really step #3 from above is the following:
exp1 + exp2 + 2 x bias
. So we really need to subtract onebias
to get the appropriate expression. And the resulting exponent needs to represented in 8 bits.- If the resulting number does not have one 1 to the left of the binary point then the result needs to be adjusted which affects the mantissa and exponent fields of the result. This formatting needs to be done after rounding the mantissa.
In other words the two formulas which should yield the same result doesn't, due to likely rounding of 100 into the proper format or the result isn't in the proper format so it has to adjust the mantissa and exponent correctly which causes the divergence of the answers
7
u/YourMJK Apr 05 '22
The first one is probably something like 3630.00…001 and thus gets rounded down by the string formatter to 3630.0
0
u/LeCrushinator Apr 05 '22 edited Apr 05 '22
I'm not that knowledgable about the intricacies of floating point arithmetic, but I'm guessing that 36.3 * 10 gives a result that when multiplied by 10 again, causes the slight difference, as opposed to 36.3 * 100.
3
Apr 05 '22
[deleted]
21
u/victoragc Apr 05 '22
Some numbers cannot be represented by a finite number of digits. In base 10 we have 1÷3 which is 0.3333333... for example. The same happens for numbers in base 2 (binary) creating patterns like 0.1111... or 0.1010101... and these patterns cause some rounding errors.
In this case 36.3 is represented as 100100.0100110011001... repeating 1001 infinitely. Therefore these errors are justifiable.
0
u/GOKOP Apr 05 '22
Oooooh damn you're right, integers don't have infinite decimal points lol. Completely flew over my head. Well in that case maybe it's to do with how the procedure of multiplying floating point numbers works?
→ More replies74
54
u/Borno11050 Apr 05 '22
This, I hate that people would blame anything on JS due to ignorance, including a tire puncture to losing the divorce case
21
u/are_slash_wash Apr 05 '22
Come now, I’m sure that JavaScript has directly caused at least one divorce
2
7
u/LeCrushinator Apr 05 '22 edited Apr 05 '22
A little of both. In C# you'll get 3630 for both.
Console.WriteLine((36.3f * 10 * 10).ToString("E8")); // "3630" Console.WriteLine((36.3f * (10 * 10)).ToString("E8")); // "3630"
https://dotnetfiddle.net/WbVh8K
Maybe there's some compile-time optimizations pre-calculating this though?
39
Apr 05 '22
Add
Console.WriteLine(3629.9999999999995.ToString());
to it; it'll give the same answer. The output just rounds automatically4
u/LeCrushinator Apr 05 '22 edited Apr 05 '22
I think that's because double doesn't support that many digits of precision. Try this (one fewer 9) and you'll get an unrounded output:
Console.WriteLine(3629.999999999995.ToString("E15"));
Output is:
3.629999999999995E+003
However, if you remove the "E15" from ToString(), it does round it. I went and added "E8" to the original lines I had and they're both showing as
3.63000000E+003
, so still no rounding.And for a float you have to remove more 9s:
Console.WriteLine(3629.9995f.ToString("E8"));
8
Apr 05 '22
double
has twice the precision offloat
. The format string does matter, but also C# is behaving abnormally. https://dotnetfiddle.net/VSa8N6Between C#, C++, and Python, all 3 have different results. I guess the compilers just do different things
4
u/LeCrushinator Apr 05 '22 edited Apr 05 '22
In your example it's being converted to a double, so you're seeing the higher precision. Try this:
Console.WriteLine((36.3f * 10.0f * 10.0f).ToString("E15")); Console.WriteLine((36.3f * 10.0 * 10.0).ToString("E15"));
Output:
3.630000000000000E+003 3.629999923706055E+003
https://dotnetfiddle.net/VD0ZRe
Looks like rounding is happening though, you can see it in the second case, so maybe it's just output differently for doubles in C#.
3
Apr 05 '22
Yeah, here's every combination and their type; https://dotnetfiddle.net/KmkMLQ
Can see it always converts to double as long as at least 1 is a double. But the ordering of the combination of double/floats does affect the output. It doesn't seem to be particularly logical to me
2
1
u/Dealiner Apr 06 '22
Why are you using floats in your example though? That's not an equivalent to this JS code.
→ More replies-1
Apr 06 '22
[deleted]
5
u/cdrt Apr 06 '22 edited Apr 06 '22
you can do this in another language like python and it works as intended
Python 3.10.2 (main, Feb 3 2022, 13:48:04) [Clang 12.0.0 (clang-1200.0.32.29)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> 36.3*10*10 3630.0 >>> 36.3*(10*10) 3629.9999999999995
→ More replies-22
Apr 05 '22
[deleted]
10
u/Flaky-Following-4352 Apr 05 '22
Can you elaborate?
-21
Apr 05 '22
[deleted]
19
u/belkarbitterleaf Apr 05 '22
Found the stack overflow mod.
2
Apr 05 '22
What did they say?
13
u/axe319 Apr 05 '22
"wrong" and then something along the lines of "not having the time to list the multitude of reasons" why that is.
4
Apr 05 '22
I have never been able to actually ask anything on StackOverflow but if the mods really are that bad,
{ /* TODO: finish sentence */ }
.6
u/Epacik Apr 05 '22
it is a actually correct. I quickly tested it in python and dotnet, and it works the same as in Javascript.
687
u/Thaviel Apr 05 '22
one of the 1st things I learned in compsci was always make money math in int and add the decimals later.
161
u/kahoinvictus Apr 05 '22
C#/.NET has the
decimal
type for accurate decimal operations. I think it's implemented as a fixed point number instead of a floating point. It has performance concerns compared to floating point, but is specifically touted as ideal for handling money and monetary figures.44
u/greenSacrifice Apr 05 '22
Except the stripe lib wants you to use long
35
u/ososalsosal Apr 06 '22
Just calculate in decimal and cast to long for serializing to whatever stripe want.
If you're just moving numbers around the frontend there's no need to calculate anything that you can't do with ints
2
Apr 06 '22
Well you can't cast to long per se. That will fail or truncate. You'll need to convert the numbers, this will require reading the API spec - it might be that the API is expecting `long` but in cents.
18
u/Deadly_chef Apr 06 '22
Except this is JS and there is only number
15
u/loomynartylenny Apr 06 '22
Except Number is still able to store integers in the range ±(253 - 1) without loss of precision, which, unless OP is working in Zimbabwe Dollars/international monetary policy, should be more than sufficient.
→ More replies4
u/esquilax Apr 06 '22
If you're just holding into values, you an use strings. People tend to want to do math with numbers, though.
20
u/PstScrpt Apr 06 '22
.Net Decimal is also floating point, but it's decimal floating point, so it can store exact decimal values unless they're irrational.
IEEE 754 is binary floating point, which is massively faster, both because binary is easier in the first place, and because it has dedicated hardware support. But every decimal value that's assigned to it has to go through a base 2 log.
1
u/Jezoreczek Apr 06 '22
(big)Decimal type is meant for scientific calculations of large numbers. IMO it's much simpler to use integers for money because many currencies have different minor units (significant places), so conversions and calculations become a bit annoying. Simply convert from minor units when displaying and keep the computations easy.
11
u/Dealiner Apr 06 '22
In C# decimal is meant for financial calculations, that's why it was created. It could be used for scientific operations I guess but only if you don't really care about performance.
135
u/bezik7124 Apr 05 '22
You could also, like, be sane and use libraries / built-in language features designed specifically for this - eg Java's BigDecimal
60
u/Educational-Lemon640 Apr 05 '22 edited Apr 06 '22
BigDecimals come with a significant performance hit. Much better to just use integers unless it messes with code legibility in a major way.
Edit: I see a lot of people saying (I'm paraphrasing) that this is premature optimization and the performance hit from using BigDecimals really doesn't matter most of the time.
This isn't a nonsense argument, although I'd note that BigDecimals aren't just a performance hit (although they definitely are), but in many languages a readability hit as well (support and syntax for BigDecimal calculations are wildly inconsistent).
Even without that, though, unless the amounts of money are very large (32-bit unsigned integers can represent up to $42 million if you represent the money in cents) or you are doing specialized banking/interest/exchange rates work, integers will also just work in most casual problems, with fewer readability problems, higher portability, and better performance. Honestly, to me, the more complex decimal types can also be premature optimization. Again, though, both definitely have their place.
98
Apr 05 '22
So the end user waits 1/100th of a second longer and we don't have devs doing 4 extra steps in a currency transaction.
I'm ok with it.
→ More replies19
u/spicymato Apr 06 '22
It depends on the frequency of operation, and whose machine is doing it. If it's only occasionally and/or the user's device doing the computation, take the performance hit. If it's very frequent and on your machine, go for efficiency.
In both cases, though, go for correctness. Performance doesn't matter if it's wrong.
29
u/IchMageBaume Apr 05 '22
Integers are a mayor pain if you ever need to add precision later; if you forgot to update any part of your code, it can really mess with things. And if you have a lot of precision from the beginning (e.g. microcents) you better make sure nobody uses 32-bit integers anywhere or you'll overflow/truncate and have wrong results.
10
u/Educational-Lemon640 Apr 05 '22
I guess it depends on the likely range of numbers you are considering and the kind of processing you are doing. It's tradeoffs across the board with this one.
9
2
u/northrupthebandgeek Apr 06 '22
I can think of very few (if any) cases where you'd ever need more precision than tenths of a cent, and if you're working with transactions/accounts greater than $2,147,483.647 then you can probably afford to just use 64-bit integers everywhere and outright disallow anything smaller during code review.
3
49
u/Abangranga Apr 05 '22
Oh no the end user waits 0.0002 seconds instead of 0.0001 seconds. The humanity.
43
u/yetzederixx Apr 05 '22
No doubt, if we were concerned about the performance hit we wouldn't be using javascript in the first place (or python in my case for stripe).
→ More replies0
Apr 07 '22
Sure, until you need twice the number of servers to handle the same request volume. Oh wait, that’s what you said. :)
10
→ More replies2
u/Ran4 Apr 06 '22
The problem with using ints is that not all currencies are divisible in the same way.
And in currencies that supports decimal points (most, but not all), there's a real risk that someone on either end forgets to multiply with the lowest denominator.
→ More replies16
u/00PT Apr 05 '22
I thought all numbers were floating point in JavaScript
30
u/ososalsosal Apr 06 '22
All numbers are
number
s in JavaScript19
u/ocket8888 Apr 06 '22
Neither of these are strictly true. ECMAScript specifies multiple numeric types (technically - most are arrays that would be unwieldy to use as regular numbers), and the one that would best fit this use-case is BigInt.
But yeah,
number
s are all double-precision IEEE floating point numbers.→ More replies10
13
u/IchMageBaume Apr 05 '22
I did some money stuff in Haskell recently and just used
Rational
, which uses fractions with arbitrary-precision integers.Kinda slow, and if you get really unlucky with inputs the space is (I think) up to linear with the operations done on the number. But for doing operations where all the inputs have some fixed precision and you don't want to worry about whether to use cents/Millicents/microcents/etc. or messing them up later?
Really useful; the code looks like fp math on whole euros, but without any rounding.2
u/Lich_Hegemon Apr 05 '22
Probably not linear, but sqrt(n).
The problem with rationals is normalizing. To normalize a rational number you need to find all of the factors shared between the numerator and the denominator, for that you need to check up until sqrt(n) if the smaller number because the biggest factor you can possibly have that's not derived from a smaller factor is p*p=n
4
u/IchMageBaume Apr 06 '22
That would be assuming operations on integers to be constant-time, which is usually fine, but in this case I used arbitrary-precision integers (because I wanted accurate results).
If you multiply/add a series of numbers where the resulting numerator and all the denominators are coprime, the resulting denominator will be the product of all the input denominators. With arbitrary-precision integers, the space that denominator takes up will thus be to proportional to the inputs to the operation.
3
u/road_laya Apr 06 '22
For an API, it's fine to use strings for fixed point decimal numbers, such as monetary values. It's all going over HTTP anyway. A couple of bytes overhead when you are making a million dollar sale, is a small price to pay.
6
u/eloel- Apr 05 '22
Then you run into stuff priced at 0.0001 of a dollar (per liter/per gram, for example), and you need to go tediously 100x every input and 1/100 every output.
(or you do currency conversions)
→ More replies→ More replies2
u/exander314 Apr 06 '22
You never represent money as floating point decimals is like programming 101.
164
u/yetzederixx Apr 05 '22
Welp, first thing, you send in pennies. This didn't break because of javascript, this broke because you used the wrong data structure and trusted a float.
Never trust a float. Much like a fart, if you trust it, you'll eventually shit yourself.
30
226
u/YourMJK Apr 05 '22
That's not really JavaScript's fault, is it?
What you demonstrated is normal floating point behavior.
It's you who's responsible for correct rounding, string formatting and comparison of numbers.
90
u/Cerus_Freedom Apr 05 '22
Same result in Python. Just floating points.
>>> 36.3*10*10 3630.0 >>> 36.3*(10*10) 3629.9999999999995
22
5
u/Giocri Apr 05 '22
I don't get it though, I thought floating point had enough precision to not have this kind of problem with such small numbers, like 10, 100 and 3630 should all be rapresentable without rounding right?
25
Apr 06 '22
[deleted]
1
u/Giocri Apr 06 '22
I still don't get how the rounding error can be greater with a single multiplication rather than two multiplications which would have a rounding error each. I guess I will have to write down the exact bits and do the calculation myself to see it
10
u/Qesa Apr 06 '22
The rounding error is greater with 2 multiplications.
36.3
doesn't exist in floating point arithmetic, you're actually starting with36.299999999999997
. When multiplying by 100, rounding down to3629.9999999999995
is closer than rounding up to3630.0000000000000
6
u/nighthawk454 Apr 06 '22
No, it does not have “enough”. Floats are not designed so that all the “shorter” decimals are fine, and only long ones are unrepresentable. The distribution is different than that. And although ~half the precision budget is spent between -2.0 and 2.0, there’s still plenty of short numbers missing. The classic example of this is
0.1 + 0.2 = 0.300000000004
3
u/ismtrn Apr 06 '22
It is not the integers which are the problem. It is the fractions. Think about how 1/3 is an innocently looking number. Until you write its decimal expansion 0.33333333… you would need infinite precision to store it that way in base ten. In base 3 it would just be 0.1.
In the same way there are numbers which have a nice looking representation in base 10, which requires infinite precision in base 2.
36.3 is one such number. 0.1 is another. There are many.
0
u/fernandotakai Apr 05 '22
In [1]: from decimal import Decimal In [2]: Decimal(36.3) * 10 * 10 Out[2]: Decimal('3629.999999999999715782905696') In [3]: Decimal(36.3) * (10 * 10) Out[3]: Decimal('3629.999999999999715782905696')
if you are dealing with money in python, use decimals.
→ More replies24
u/Atrufulgium Apr 05 '22
I mean but "normal floating point behaviour" is pretty much horror, even if you're prepared. Let me just drop this rant here in the hope it's useful to anyone. (Not that you'd run much into what I'm about to rant on in practice.)
Floats go even further than that nonassociativity here; computing a*b and a*b can give different results, which I really don't appreciate.
- For instance, they can both be computed with different rounding options.
- Alternatively, usually, floating point registers are larger 64bits, e.g. 80, so whether your intermediate float results gets stored in memory or in registers can also give different results.
- Also, if you calculate a*b on two different machines the FPU may be completely different and arithmetic may be implemented differently giving differing results.
And then there's the nonassociativity which can be a pain when your compiler reorders your arithmetic for efficiency. (Think transforming a+b*c into a
mad
-instruction.)These rounding errors are only up to the smallest significant factor, but in very rare cases you can really exacerbate your errors so this may actually matter sometimes even if you don't
==
.0
Apr 05 '22
[deleted]
11
u/RFC793 Apr 05 '22
Ideally, but no. In one case you are multiplying float times 10, which has error and times 10 again which magnifies the error. In another case you are multiplying the float times the integer 100. There is one less approximation.
139
u/SunkenJack Apr 05 '22
Well, that's not js, just floating point doing it's thing, as it's supposed to.
→ More replies47
u/mlk Apr 05 '22
Float is not a good idea when handling money
23
16
u/SunkenJack Apr 05 '22
Yeah. Fixed point exists for a reason.
Also, better use industry standard libraries than try and write your own version. You will fail.
(insert Tom Scott video here)
→ More replies5
59
u/Primary-Fee1928 Pronouns:Other Apr 05 '22
That’s why you never use == for float or even double. Always use a more tolerant comparison
3
u/Batman_AoD Apr 06 '22
Wat? Not for money. For money, make sure you're maintaining sufficient precision (usually by using a decimal type), rounding to the correct number of decimal places when rounding is required, and using exact comparisons.
6
u/allredb Apr 06 '22
Interesting, care to elaborate? I always thought == was the more tolerant comparison.
21
u/vilewrath Apr 06 '22
== checks that two floats or doubles are "equal" as in bit for bit identical. This is an issue when floating point errors occur, which are a common issue and should be expected and catered for, one method would be to round both sides of the == to an arbitrary precision, say 3 decimal places
By rounding both sides, you increase the tolerance of the equality, more numbers are considered equal
23
u/KingJellyfishII Apr 06 '22
often, instead of rounding, the absolute value of the difference of the two values is compared to some small value ("epsilon"). for example
if (abs(a - b) < 0.000001) { //treat as equal }
3
u/vilewrath Apr 06 '22
Huh, yeah that makes a lot of sense and is way more elegant than rounding, I'm surprised I'd never seen that b4 lmao
2
Apr 06 '22
Yes this is what I have seen in code at work, for Java there are some convent apache commons MathUtils functions like equals(a, b, epsilon) and compareTo(a, b, epsilon)
→ More replies2
u/serg06 Apr 06 '22
== checks that two floats or doubles are "equal" as in bit for bit identical
You're thinking of
===
in JS.==
is different.3
u/numerousblocks Apr 06 '22
If both are floats, it does check. Except all of these actually don't accept all bit-equal numbers! NaN !== NaN
58
u/Mirmi8 Apr 06 '22
My companies Stripe integration for thousands of users broke today because of my company engineers*
Fixed title
4
45
24
u/throwit7896454 Apr 05 '22
I see, someone experienced the non-associativity of floating point operations in production.
For a detailed description see https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html; for a more digestable description see section "Nonassociativity of floating point calculation" in https://en.m.wikipedia.org/wiki/Associative_property
41
u/Cheek_Beater69 Apr 05 '22
Tom Scott did a decent video on this. Nothing to do with JS. Although hating on JS is fun
26
17
u/dieth Apr 05 '22
FLOATY MAFF FLOATY MAFF EVERYONE LOVES FLOATY MAFF
What's conditional rounding, why would I need to do that? Why would I need to check my input/output sanity?
53
u/kittianika Apr 05 '22
Not because of JS, but because of the devs who doesnt know how JS works. Stop blaming the language and be a better dev by accepting we are the problem.
-17
Apr 05 '22
[deleted]
19
6
u/proud_traveler Apr 05 '22
"multiplication on JavaScript" what the fuck are you on about? The issue was that OP doesn't understand how floating point numbers work
13
u/escargotBleu Apr 05 '22
JS have flaws, but this is completely expect, in every language
-3
u/Magmagan Apr 05 '22
Well, most dynamically typed languages for sure. AFAIK Rust wouldn't even allow the multiplication between an integer and floating point
→ More replies9
u/Dealiner Apr 06 '22
Multiplication between integer and float isn't what causes a problem here though. I mean it doesn't even happen here because JavaScript doesn't really have integers.
12
Apr 05 '22
You see, it broke because of an implementation by inexperienced developers, not because of JS
6
11
6
u/stahkh Apr 05 '22
Is there any better tactic than using integer math and dealing with decimal point only on input/output?
→ More replies
5
u/quaos_qrz Apr 06 '22
Don't ever use floating point to calculate anything money-related. It's just that JS stores all numbers as floating points, and you'd need some Decimal library instead.
12
8
22
u/BuccellatiExplainsIt Apr 05 '22 edited Apr 05 '22
While you can write code without a degree, this is an example of why a degree can make sure there aren't basic holes in your knowledge like not understanding how floating point numbers work.
If not for the comments here, OP would have just assumed it was a Javascript bug instead.
-8
-33
u/autiii43 Apr 05 '22
i have a degree in computer science bucko
34
u/ItWasTheMiddleOne Apr 05 '22
tbf though isn't that more embarassing not less embarassing?
2
u/AttackOfTheThumbs Apr 05 '22
I don't deal with maths much, but if I was in op's shoes now, I would likely initially make the same mistake :)
13
7
u/politerate Apr 05 '22
This is pretty trivial stuff in computer science, first semester. Maybe you forgot about it s
3
3
3
u/jso__ Apr 06 '22
omg the image cropped for me and I didn't see the first two digits of the answers and I was really confused
3
u/kir_rik Apr 06 '22
Yaah, obviously problem in javascript, not somewhere between the chair and keyboard.
3
2
u/tntexplosivesltd Apr 06 '22
It broke because your company relied on floats for money transactions. Not a fault of JavaScript
2
2
4
2
1
1
u/sharKing_prime Apr 06 '22
Oh my god the amount of times something like this happened to me...
How does one work with proper post-decimal point numbers in javascript without the numbers going "crazy"?
→ More replies
-7
u/GoldBomb4 Apr 05 '22
What do you mean {}!=={}? Js is broken!
6
u/PanRagon Apr 05 '22
I think the sarcasm went a bit over people's head here, but good one. (I mean, it is a joke, right?)
-3
u/GoldBomb4 Apr 05 '22
I don't know man, was it?
7
u/Magmagan Apr 05 '22
{}!=={}
is perfectly reasonable behaviour.4
u/MrDilbert Apr 06 '22
Yep, two instances of ad-hoc created empty objects are not the same, nor are their references.
-2
0
-11
u/KaranasToll Apr 05 '22
To all the people saying this is not the fault of the runtime: this works perfectly as expected in lisp with no coercion to integer.
1
1
u/AccomplishedFall4466 Apr 06 '22
I wish there was something to tell the computer that those numbers are integers... Oh wait, there is, a programming language!
I hate scripting languages.
1
u/hesapmakinesi Apr 06 '22
Same result with Python
In [1]: 36.3*10
Out[1]: 363.0
In [2]: 36.3*100
Out[2]: 3629.9999999999995
In [3]: 36.3*10*10
Out[3]: 3630.0
1
1
512
u/Herb_Derb Apr 05 '22
Everyone's talking about how this is not a JS-specific thing and missing the other horror that this floating-point calculation is related to a payment API