|
If I understand you correctly, then you'd be in favor of your own library/class/etc. to wrap this then? For JavaScript, there's no way I'd use most libraries as they're too bloated for this. Rolling one's own would be an option, but the end result would still use approximation inside the rational class right, if there was an expression that involved a floating point?
Keep in mind, I'm not a math major.
Jeremy Falcon
|
|
|
|
|
No approximation until the very end. You keep numerator and denominator integer values and you operate with those as you learned to do it with fractions in high school.
Edit again: a few days ago I had to do something like that in JavaScript but for complex numbers. If you are interested, it’s here: Numerical Examples - Modified Stereographic Conformal Projection[^]
Mircea
|
|
|
|
|
Gotcha
Jeremy Falcon
|
|
|
|
|
I found the good link for the JS code I was talking about before: https://neacsu.net/js/mod_stereo.js[^] Look at the complex class and you can probably model a rational one based on that.
Mircea
|
|
|
|
|
Thanks for the link. My only concern with doing stuff like that, is if I start using arrays to store the fractional parts, this app is gonna slow down. Keep in mind, for this app it'll need to do thousands (potentially) of calculations per second. I may just have to settle for close enough, for this specific app.
Jeremy Falcon
|
|
|
|
|
Thousands of calculations per second still shouldn't take any time. Come back when you're talking billions and we can start to use SIMD or even WebGPU to do some heavy lifting.
Meanwhile you need to ask stakeholders when the rounding may happen. It's pretty standard that individual transactions have tax rounded, for example, and it must stay consistent. There are multiple strategies for rounding, including even or odd rounding, and it shouldn't be chosen at random. Don't forgo correctness because of some desire for speed that's ill-placed.
|
|
|
|
|
If I needed millions, I'd be using C or Rust. But point taken...
Jeremy Falcon
|
|
|
|
|
Good approach. But again be consistent.
"A little time, a little trouble, your better day"
Badfinger
|
|
|
|
|
In good old days, we had DOUBLE PRECISION in Fortran and double in C. At least these had better precision than REAL and float .
Somehow, it seems that the designers of later languages put more emphasis on string s, perhaps, because layman-type of users/applications started outnumbering scientific/numerical users/applications.
|
|
|
|
|
Amarnath S wrote: we had DOUBLE PRECISION in Fortran and double in C.
Even with binary DOUBLE PRECISION, you would get errors in accounting formulas. This is why COBOL was specified to have a decimal type.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Yes sir.
"A little time, a little trouble, your better day"
Badfinger
|
|
|
|
|
Sometimes I do wish JavaScript had better types like that. I can push a precision to about 9 or 10 in JavaScript before the storable value becomes too small to be worth while. Good enough for kiddie stuff at least.
But yeah, also what Daniel said.
Jeremy Falcon
|
|
|
|
|
Javascript's innate number type is but an approximation - everybody will agree. But the serialization of those numbers in JSON makes it worse. For example, what is really meant with 0.67, 0.667, ... , 0.66666666666667 ?
Does 0.67 mean exactly 67 cents and is 0.66666666666667 to be understood as an approximation of 2/3? And does 0.667 also stand for 2/3? What does the number of decimals tell about the underlying intentions?
JSON should have a standardized notation for lossless serialization of floating point type numbers. Even C has that: the %a printf format for double in hexadecimal notation. And talking about shortcomings in JSON: please also provide a notation for bignums - both integer and rational ones.
|
|
|
|
|
This is why COBOL has a decimal type.
Your approach of using integers to represent currency will work, subject to a few caveats:
- Accounting rules require that calculations (e.g. multiplication, division) be performed with greater than 1 cent accuracy (5 decimal places, IIRC). This allows interest calculations, currency conversions etc. to work properly.
- Rounding is performed using accounting rules - round to nearest or AWAY. The difference between this and round to nearest or EVEN is when the fraction is exactly 0.5. If this case, one rounds AWAY from 0. For example, 3.145 would round to nearest or EVEN as 3.14, but round to nearest or AWAY as 3.15.
There may be other rules for accounting, but these are the major ones.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Daniel Pfeffer wrote: This is why COBOL has a decimal type. Never thought I'd say this about COBOL, but that's cool.
Daniel Pfeffer wrote: There may be other rules for accounting, but these are the major ones. Thanks for this man.
Jeremy Falcon
|
|
|
|
|
|
I was waiting for that. Had to give COBOL some love though.
Jeremy Falcon
|
|
|
|
|
Jeremy Falcon wrote: Had to give COBOL some love though.
Rightfully so, COBOL is better than its reputation. And still in development, latest version is COBOL-2023.
|
|
|
|
|
I remember COBOL. I worked for an accountant/programmer during grad school.
His clients used NCR COBOL machines with COBOL interpreter language.
Bullet proof.
"A little time, a little trouble, your better day"
Badfinger
|
|
|
|
|
Daniel Pfeffer wrote: There may be other rules for accounting
In certain domain spaces there are regulations that must be followed. And they can vary by political region.
|
|
|
|
|
.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.
|
|
|
|