|
.toFixed(x) should do the trick.
And maybe even +(0.1 + 0.2).toFixed(2) , which displays 0.3 just fine
A user never wants to see more than three digits anyway.
But ultimately, I do all my calculations in C# that has a decent decimal type.
I once had a customer who wanted to calculate VAT for each sales order row and then got mad the total didn't add up due to rounding errors
|
|
|
|
|
Sander Rossel wrote: .toFixed(x) should do the trick There's actually some rounding errors you'll find with that. I have a means to do the rounding, just curious to know what's peep's favorite way.
Sander Rossel wrote: But ultimately, I do all my calculations in C# that has a decent decimal type. Win for C#. This project is in 100% Node, so me no get that.
Btw, here's the routine I use to do more accurate rounding, if you want it...
const MAX_DECIMALS = 16;
export function roundOff(number: number, decimals = 0): number {
const exponent = Math.min(Math.max(decimals, 0), MAX_DECIMALS);
const factor = 10 ** exponent;
return (Math.round(((number || 0) + Number.EPSILON) * factor) || 0) / factor;
}
Sander Rossel wrote: I once had a customer who wanted to calculate VAT for each sales order row and then got mad the total didn't add up due to rounding errors Good times. Good times.
Jeremy Falcon
|
|
|
|
|
Somehow, I've never really needed this.
I consider myself a lucky man
I always wonder why JavaScript adds new stuff such as classes, let, const, and what have you, but not a decent rounding method, or an array.remove method.
Why does an array have reduce, join and flat, but not remove!? I keep googling "javascript array remove element", oh right, splice (or was it slice?), indexOf, 1
JavaScript really seems to be missing the basics, the bare necessities even, but somehow it keeps adding junk most people will never need.
|
|
|
|
|
There is a remove method for the last single element. It's called Array.prototype.pop. If you want to remove chunks of an array at a time, as you mentioned there's Array.prototype.splice. Not sure why the no bueno, just because it's called splice rather than remove .
Jeremy Falcon
modified 23-Mar-24 13:02pm.
|
|
|
|
|
Those aren't remove functions.
You forgot shift, which removes the first element.
However, I very rarely need to remove the first or last element specifically.
If I have a reference to an element I don't even know its index, I just want to be able to remove it.
It's just JavaScripts way of saying "it's an array, but you can abuse it as stack or queue."
Splice is also something different entirely.
You need an index and the number of items you want to remove starting at that index.
I can never remember it: array.splice(array.indexOf(something), 1); .
It can also be used to add new elements at the designated index, so clearly not a remove.
The slice methods just returns a portion of the array between the specified indexes, and it sounds too much like splice to be able to remember clearly which is which.
Someone new to JavaScript would never guess what it does or how to use it.
I just want to say array.remove(something); and it should remove something.
A remove function is easy to remember, easy to use and clearly conveys your intent.
I don't care if it just does array.splice(array.indexOf(something), 1); internally, I just want to be rid of that awful syntax.
Everyone who says "splice is JavaScripts remove function" is dead wrong.
|
|
|
|
|
Sander Rossel wrote: You forgot shift, which removes the first element. Didn't forget it man. It's an Internet post... not a book. I was giving a few examples. Do better than the kiddie crap on CP.
Sander Rossel wrote: I just want to say array.remove(something); and it should remove something. Well that's enough reason to hate an entire language. #sarcasm
Sander Rossel wrote: Everyone who says "splice is JavaScripts remove function" is dead wrong. Well, what I find with programmers, they lack enough maturity to not be overly emotional about crap. And they love to hate to feel intelligent or superior (usually the opposite). I'm going to give you three examples that don't require much thought, you'll probably not change your mind at all but it doesn't mean I'm wrong... bias and hate by non-experts is bias and hate after all...
const data = [1, 2, 3, 4, 5];
delete data[2];
console.log(data.filter(x => x));
console.log(data.filter((x, i) => x !== 2));
data.splice(2, 1);
console.log(data); Also, keep in mind, C# doesn't have a strong sense of immutability, like JavaScript does. Not that you can't mutate, as given in the examples...
I suggest you try running that code before perpetuating the unfounded hate.
Jeremy Falcon
|
|
|
|
|
Also, this is why I post less and less on CP. I can't post anything without someone coming along who knows little about the language and give their hateful opinion on JavaScript. It's a waste of time man, to repeat the same conversation over and over again for years.
Jeremy Falcon
|
|
|
|
|
Forgot to mention why the use of Number.EPSILON. Consider this:
1.005.toFixed(2);
Math.round(1.005 * 100) / 100;
Number.EPSILON handles these edge cases in a way that's small enough to not bother non-edge cases. Just be careful with using it though for every day calculations as it's not perfect to always rely on. But for fixing these edge cases it works great.
Jeremy Falcon
modified 21-Mar-24 12:43pm.
|
|
|
|
|
Had a similar problem before… It was a percentage breakout like VAT where they wanted it to always total to 100%. The customer demand was that you sort by original value (smallest to largest), calculate the first n-1 percentage per line item, last/biggest nth item is force set as 100-(sum (n-1 line item percentages) )
That way when you exported the values to Excel, it all balanced. Just hope the customer does not add formulas back in and notice that the biggest row is off by +/-0.01 in the calculation.
|
|
|
|
|
Jeremy Falcon wrote: complete accuracy on numbers
So, not a government project then?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Ha ha ha ha. Nope.
Jeremy Falcon
|
|
|
|
|
Okay, I'm now having flashbacks to my numerical methods class in college. One of the central points in the course was that managing precision was important, but it had to be appropriate to the calculation.
You've hit on that with currency. I remember a story where a programmer at a bank embezzled a lot of money based on harvesting roundoff error in the bank's software that he wrote. There are certifications and legal mechanisms that define how calculations are performed now. Scientific computation is similar. It's hard to imagine the analysis that the Large Hadron Collider experiments require, since the data of interest is embedded in unbelievable amounts of noise.
Heck, it's even a problem in my world of commercial ink-jet printing systems. Our internal unit of measurement is µinches (micro-inches) in a 64-bit signed integer. We deal with positioning data in 1/3600ths of an inch that can be noisy, and our resolution is 600 dots/inch. Using µinches solves a lot of scaling issues.
Software Zen: delete this;
|
|
|
|
|
This is the only correct answer: it has to be appropriate to the calculation. In some cases, perfect precision is not even mathematically possible (e.g. pi = ratio of a circle's diameter to circumference, or anything involving it like sin() or cos()).
Rational libraries are great when appropriate, but (a) they can be a lot of computing for no real world benefit, and (b) if you have any intrinsically irrational number like pi in there anywhere, their usefulness instantly becomes limited (or you have to factor out the irrationals and express the answers as ratios of them...)
So, yeah, in real life, calculate at higher than needed* precision and round to needed precision. For accounting, use appropriate accounting rounding rules for exact 0.5 values.
*what precision? Max total of your errors all added and multiplied together appropriately according to the calculations involved must be less than half of the actual final precision.
|
|
|
|
|
"floating point precision" is an oxymoron. Which is why I don't do math in JavaScript unless I don't care about rounding errors.
|
|
|
|
|
Yeah, but to be fair... this issue is with all languages.
Edit: Unless you mean the decimal type in C#? In which case... totally gotta give props to that.
Jeremy Falcon
modified 21-Mar-24 11:31am.
|
|
|
|
|
Yes exactly, the decimal type in C#. I was going to mention it but it seemed like the context of your question was JavaScript.
And for SQL, there's a really interesting post here[^] about how to use the money and decimal types correctly. Learned something looking that up!
|
|
|
|
|
I work in engineering applications so my answer is "I don't use floating point arithmetic", everything is fixed point - many microcontrollers do not have an FPU at all and what I do is mostly real-time so forget software emulation. Any desktop tool has to provide or receive data from these systems so it's mostly fixed point until it's time to show to the user.
On non engineering applications I just use floating points as they are, if I have qualms about precision I just use double or long double and call it a day - I don't work on servers or high throughput / low latency services so I just don't care.
GCS/GE d--(d) s-/+ a C+++ U+++ P-- L+@ E-- W+++ N+ o+ K- w+++ O? M-- V? PS+ PE Y+ PGP t+ 5? X R+++ tv-- b+(+++) DI+++ D++ G e++ h--- r+++ y+++* Weapons extension: ma- k++ F+2 X
The shortest horror story: On Error Resume Next
|
|
|
|
|
One thing to consider, there is a worldwide standard that most operating systems follow, IEEE 64-BIT. To me it wouldn't be unreasonable to follow that. Anyone situation that requires more would be highly specialized.
|
|
|
|
|
I'll check it out. Thanks.
Jeremy Falcon
|
|
|
|
|
When seeking consistency, I would wrap all of that in a utility class. This way I know it's consistent and works the same everywhere. If I need something a little different, then I either overload or add a default parameter as the occasion requires.
I agree that storing the numerator and denominator would be the best way to prevent most headaches. In C#, I would use a Fraction struct for this (home grown if one doesn't exist already). Only collapse the fraction to a primitive type as necessary. This also has the benefit of letting you use money with a decimal value, so you don't have to do the extra math to get the cents back.
Speaking of money, you only have to store 4 decimals with money to be accurate for accounting purposes. I deal with fiduciary escrow accounts for my job, and that's all we've every used. Never had a problem being out of balance by a penny in 24 years. However, we don't do multiplication and division on the money. I don't think that would change much though as long as you kept the division and rounding to the end of the math problem.
Bond
Keep all things as simple as possible, but no simpler. -said someone, somewhere
|
|
|
|
|
Matt Bond wrote: When seeking consistency, I would wrap all of that in a utility class. This way I know it's consistent and works the same everywhere. If I need something a little different, then I either overload or add a default parameter as the occasion requires. Ultimately, that's what I did. Except they were utility functions because I'm more functional than oop. Same concept though.
Matt Bond wrote: I agree that storing the numerator and denominator would be the best way to prevent most headaches. In C#, I would use a Fraction struct for this (home grown if one doesn't exist already). Only collapse the fraction to a primitive type as necessary. This also has the benefit of letting you use money with a decimal value, so you don't have to do the extra math to get the cents back. Yeah, it's an awesome idea. A pretty cool piece of code was posted earlier for rational numbers. My only concern with a language like JavaScript is the speed of that. In something like C/C++ I wouldn't think twice about using it.
Matt Bond wrote: Speaking of money, you only have to store 4 decimals with money to be accurate for accounting purposes. Whoops. I was storing 2. Thanks for this.
Matt Bond wrote: However, we don't do multiplication and division on the money. How do you do arithmetic on it then? Like, to calculate interest then?
Thanks for the reply btw.
Jeremy Falcon
|
|
|
|
|
The program deals with escrow accounts for settlement of a house sale. We just have to track incoming and outgoing money to make sure 1) each sale balances, 2) everyone gets paid the right amount, and 3) the entire bank statement balances. Thus, no multiplication nor division.
For a different part of the program, we do calculate per diem and monthly payments from an interest rate. The interest rate goes out to 6 decimal points, just in case (normally only 3 are used because they are multiples of 1/8 or .125 in the USA). The math is straight multiplication, then rounds to 2 decimals using 4 down/5 up rounding. We round at this point because this result is displayed to the user and summed with other amounts for a grand total. If we stored to 4 decimals, then we could have rounding errors appear in the grand total.
Bond
Keep all things as simple as possible, but no simpler. -said someone, somewhere
|
|
|
|
|
Thanks for the reply man. It was helpful.
Jeremy Falcon
|
|
|
|
|
Financial apps as far as I know use four decimal digits during calculations to avoid problems with only two, then round at the end.
|
|
|
|
|
Yeah, someone else just posed this. I'm gonna do the same then. Thanks man.
Jeremy Falcon
|
|
|
|
|