-
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
BigDecimal with division and other operations which need to round #13
Comments
I'm not entirely sure if it's a good idea, but there is another option (or rather a variant of Java-like approach) - use precision based on product of precisions of the multiplication factors:
I'm not sure if it's intuitive enough, but it's for sure more convenient than using method instead of operator, it gives more control than Ruby-like approach, and it's a nice parallel to multiplication. |
@qzb Thanks for including this option; we should definitely be considering this option among the three others above. It makes sense formally, considering the precision rules for other operators. Personally, I find |
@littledan Even worse, according to these rules
It gives some control over result's precision, works with existing operator, but starts to be pretty convoluted... BTW, it's worth mention that we can have both Java-like and Ruby-like operations, one using |
@qzb This may be a reasonable compromise. I think this is what Ruby does. The ugly part is that we have to arbitrarily choose this constant (e.g., 10). |
FWIW, here was my short thought process upon hearing of this conundrum:
|
What about static field which could read / write in |
@domenic Actually splitting money is not a good use case for dividing. Let's assume you are trying to split 10$ between three people, you have to end up with one person which pays 3.34$ instead 3.33$. When comes to splitting money you want some kind of div/mod or partition operation described by littledan in 3rd point of this issue. It could work like this:
|
@MaxGraey AFAIK currently specification doesn't include even single (writable) constant like this and adding one would probably be pretty controversial. Also it sounds like a method for producing really nasty bugs, since any of your dependencies could change it. If some minimal precision is chosen we should definitely add constant like this, Number already have 8, but it should not be writable. |
Yeah, I don't think we can have a global setting for these sorts of things. For one, primitives live outside of any particular JS global object, so they couldn't even reference that. But stepping back a bit, global settings are just the enemy of composability of different pieces of code, which is what the JS ecosystem is based on. |
Just for curious, why not big fraction (someone actually implemented that with big int) instead? If non 10 based denominator is allowed. 1.0040 is just 10040 / 10000. Not got rounded (Because you don't need to) Allowing non 10 based fraction will also makes something 1 / 3 + 1 / 3 + 1 / 3 works as anyone would expect(the computation will be more expensive though). |
I haven't seen it proposed elsewhere, so here goes. You could have a
In order to use the This syntax is quite ugly though, and quite verbose. And I suppose it'd be impossible to support something similar for your own implementations if operator overloading is ever standardized. |
This is really important. Particularly for division, siginificant figures makes more sense. In SQL,
I quickly browsed through the README but it didn't describe "precision" well. Using scale/fractional digits/decimal places for division doesn't sound like a good idea, //This is just 0.00001m
const x = 1.00m / 100000.00m Using multiplication of decimal places gives us 4 decimal places Whereas, if we went with significant figures, we'd get The question of "how many significant figures?" then comes up. Maybe something like for Even though "significant figures" usually does not mean trailing zeroes, maybe it might be more intuitive to include trailing zeroes for the definition here. The result will have So, in the above example, maybe 2 fractional digits + 2 fractional digits + 4 leading zeroes = 8 fractional digits in result So, while figuring out the decimal places for addition, subtraction, multiplication is easy and intuitive, for division, it might be better to not think in decimal places but in terms of significant figures (including trailing zeroes). |
I think we can consider another option there, that is to use Ruby-like approach (i.e choose an arbitrary amount of extra decimal places) when the result is a non-terminated expansion (e.g. What are your thoughts on this? |
The simplest use case I know of to think about decimal arithmetic is TPC-H Query 1 (simplified): If you think about how a store will do this, they will round each price in your order to the nearest penny after applying discount & tax, and then sum up the list of stuff you bought. They aren't going to retain fractional cents on each item to accumulate in the sum. So generally, you want to do decimal arithmetic with some fixed precision & scale across a set of operations (for currency, scale = 2). I think it's likely that you want to specify the precision either for some large scope (eg. everything nested within this block, global/thread scope, etc.) or you specify it when you create / declare a variable (so you can create a currency "type" with scale = 2 for arithmetic on currency). Specifying the precision on each divide operation is really horrible, and likely to create bugs for cases where you really want this large class of objects to be operated on with a particular precision/scale. |
Fixed-precision division is a real brain-bender. But sometimes, I really want it. Given these two realities, I would be totally happy with a |
What's the result here? |
It would be 0.99...999, with the number of 9s determined by some kind of context paramter/second argument. (Of course,)
I agree! With division, the need for a second parameter is clear. That makes things a bit bulkier with the syntax, but so much clearer semantically that it's worth the payoff, I'd say. (By the way, for the Decimal128 approach to decimals -- which, I realize, this thread is not about -- division does work without an extra "number of digits" argument. The number of significant digits you get in the result is bounded from above by 34, which is the number of significant digits that can be represented in a Decimal128 value.) |
Division is a bit of a conundrum with arbitrary-sized decimal types. This was discussed in the 2017 TC39 presentation. There are two basic approaches I've seen in the ecosystem:
I'm not sure what to do here. I've even considered whether this is the straw that breaks the camel's back, requiring 128-bit IEEE 754 decimal. What are your thoughts?
The text was updated successfully, but these errors were encountered: