-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Completely remove NaNs, infinities, signed zeroes and quantums. Remember their original motivation #172
Comments
For money calculations, these
I would much rather get a |
The problem is not NaN, Infinity etc the problem is lack of tools to manage them. You don't need exceptions. You need functions that pass-through unless ?. // I don't know the spec well so take this with a pinch of salt. This is how I imagine it would be handled
const decimal = /* do stuff */ new Decimal128(...) /* do stuff */
const value = Number(decimal) // correct me if I'm wrong.
const result = Number.isNaN(value) ? 0 : value
// It would be better to have a fns similar-ish to these
const value = Number.ifNaN( Decimal128(...), 0)
const value = Number.ifSignedZero( Decimal128(...), 0)
const value = Number.ifInfinity( Decimal128(...), null)
// or something like
const value = Number.safe(["NaN", "signed-zero", "infinity"], Decimal128(...)) // Default desirable behavior is managed as floats
const value = Number.safe(["NaN", "signed-zero", "infinity"], Decimal128(...), [0,0,false]) // Custom behaviors and we can have
// More types of undesirable number outcomes, probably throw in a callback for better management. My argument is really that It's important to have some kind of solution decoupled from "Decimal" as a float and that all those undesirable values are necessary. |
@julienetie how do your examples address the type of bugs I mentioned in my comments? The problem with I've never encountered a legitimate use case for EDIT: divide by zero returns |
@julienetie, your arguments are probably good for binary floating numbers, but not for decimal floating numbers. Decimal floating numbers are for money, and I don't see a single use case for infinities and NaNs.
1/0 is infinity and 0/0 is NaN. At least this is true for usual IEEE 754 binary floating point, I don't know whether this applies to IEEE 754 decimal floating point (and, alas, actual IEEE 754 standard is behind a paywall) |
@boronine NaN only appears to be silent because JS has no number safety methods. There is no safe way to handle undesirable number results in JavaScript without custom helpers or boilerplate code. @safinaskar @boronine All those values are useful for conditionally deciding what type of outcome you want. try {
new Decimal128(value1).divide(value2);
} catch(e) {
// Uncaught RangeError: Division by zero
} Hopefully this makes it easier to understand why JS should be more reliant on methods/ operators oriented around safe numbers than number errors. (Consider how modern languages use operators to treat null, nil and undefined values) But I do understand your stance, the above is also the behavior of BigInt is not intended as a final result. We can't even log
@boronine E.g. If you have to output Assuming your total derives from |
@julienetie you still have not addressed my concern.
But what if you FORGET to do a NaN check? How do your helper functions prevent silent failure?
Exceptions like
The solution is for Decimal constructor to throw an exception when instantiated with |
@boronine Are you understanding my concern? In real-world apps, you have the problem of devs using Try/ catch should not be the solution for undesirable numbers on the web platform. Modern systems languages are mitigating various number errors common in C, why exactly are we increasing them?
If you forget then the user gets NaN. NaN is bad, but complete breakage is 10x worse.
I strongly disagree.
Same applies, but what if you forget? |
Why? If you're worried of receiving a
Every language that I've ever used halts execution when dividing integers by zero precisely because it's the safer thing to do - JS bigint, Python, Java, Rust, Zig etc. Can you give a counterexample?
By the time you get a
If you forget, you get an exception that notifies you of the bug and even tells you exactly where it is by means of stack trace. You DON'T need to handle the exception, you just need to FIX THE BUG that caused it in the first place. |
Current version of the spec includes NaNs, infinities and signed zeroes. So, we would like to ask a question: why they was introduced originally? Here is the answer.
First, they was designed for calculations, which often appear in physics, engineering and calculus, for example ( https://en.wikipedia.org/wiki/IEEE_754 ):
In other words, if you calculate
1 / (1 / 0)
, then you will get0
, and this is what you likely expected (at least in physics).Second, they are designed for programming languages without exceptions, so "always produce some answer" was a requirement.
Neither of these reasons applies to our proposal. Decimal type is designed not for calculating engineering formulas such as above (there are normal binary floating point numbers for this), but for calculating money. And JavaScript does have exceptions.
So, I propose full removal of NaNs, infinities and signed zeroes.
You may say "but IEEE 754 Decimal128 has NaNs, etc". Yes, it does. This is just cargo cult. It seems they just copied everything from binary floating point numbers without thinking. This is just an error. So, let's fix this error! This will not create significant burden for implementors. They just will throw exception if they get NaNs or infinities.
Also, I propose removal of quantums. I don't know what is their original motivation, but I suppose their motivation was engineering, too.
Let's assume I measured length of pencil and said "it's length is 10.00 cm". What does 10.00 mean? Why there are extra zeroes here? "10.00 cm" means that length of pencil is between 9.995 cm and 10.005 cm (see https://en.wikipedia.org/wiki/Significant_figures ). I. e. extra zeroes here convey information about precision. But, again, all these applies to physics and engineering. All these doesn't make any sense for money. There is no difference between 10.00 usd and 10.000 usd. Both numbers mean exactly 10 usd with infinite precision.
So my proposal is: completely remove quantums. I. e. make them absolutely unobservable (it is okay if implementation uses them internally if they are not exposed).
You may say: "but what if user wants to convert monetary number to string with extra zeroes? What if he wants to get string
"10.00 usd"
?" This question is completely unrelated to quantums in their original form. Again: quantums are needed for tracking precision/accuracy as result of physical measurements. They have nothing to do with printing strings like "10.00 usd" on a screen. If you want to get string "10.00", just create custom formatting function. But don't carry quantum with number.You may say: "But other libraries for decimal numbers have quantums, for example rust_decimal ( https://crates.io/crates/rust_decimal )". Yes, it does. And this is error. They copied well-known engineering convention of significant figures to their library without thinking.
Now useful links:
The text was updated successfully, but these errors were encountered: