-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Use decnum for addition #1997
base: master
Are you sure you want to change the base?
Use decnum for addition #1997
Conversation
This isn't enough. I've already implemented simple operations once, and what you are missing is changes to the parser.y where the constant folding is taking place. |
Yeah, I left a note for that in my PR comment- I haven't gotten to doing it yet, and wanted to vet out an implementation for actually doing the addition first. |
Indeed, I've somehow glanced over that phrase. Cool |
Do you have a clear view at which operations should be implemented lossless? In the discussion before I've mentioned just the addition (including subtraction) and comparisons (already implemented) |
My thoughts were to do just the basic arithmetic operations: I've encountered a pretty rough issue with my digit calculation for addition, though- it's tricker than it appears. (How many digits is |
Re. digits calculation for the result, to my understanding for |
OK, I haven't analyzed the example correctly. You are right, we'll need to add some logic to calculate the upper digit bound. I think we need to calculate the actual digit bounds for every number given its exponent and take the resulting range:
Then for |
Agreed about the mantissa, but I think that might be desirable.
That's what I remembered from school, too, but it turns out that only works if the two numbers have the same exponents. 😞 I've been doing some digit math, and I think I have the right approach now: Let's assume that We're interested in knowing how many digits are between the most significant digit of The position of the MSD of Let's fix that ordering requirement: Really, what we're interested in is the distance between the MSD of the two numbers and the LSD of the two numbers. So the math really becomes this: It works with negative exponents, too:
Some other notable examples:
Edit: Ha, looks like we both got here at around the same time |
yeah.. I've spent some time searching for appropriate library functions in the decNumber but apparenly they haven't gotten any. I had been thinking of using the My only concern is whether the library will be smart enough to optimize the exponent as a result of the operation. The thing is, it might just use one of the operand's exponent and then end up with non-optimal digit count, throwing an exception when checking that the context doesn't provide enough storage. |
Had this thought as well- I'll craft some test cases for it to see what happens. |
If that's the case then we'll need to perform one additional operation - convert one of the numbers with |
Ah, wait, I make a new number for the result with the number of digits we calculate- I don't expect we'll have much in the way of issues. We may want to go ahead and normalize these numbers after the addition, though: I'm not concerned about normalizing after addition, because we're already doing math at that point. |
Pushed up another commit that uses the new approach for calculating the new number of digits and also reduces the resultant number. It might be a bit expensive to perform for every bit of arithmetic, but this is the only time where we know it's safe to perform (if we did it at print-time, we wouldn't know if the trailing zeroes were from the input or not). |
@@ -225,7 +225,7 @@ static block constant_fold(block a, block b, int op) { | |||
int cmp = jv_cmp(jv_a, jv_b); | |||
|
|||
switch (op) { | |||
case '+': res = jv_number(na + nb); break; | |||
case '+': res = jv_number_add(jv_copy(jv_a), jv_copy(jv_b)); break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it too late to copy the arguments here? jv_cmp above has already consumed those, hasn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it has. I'll fix that.
src/jv.c
Outdated
|
||
decContext *ctx = DEC_CONTEXT(); | ||
decNumberAdd(&nlit->num_decimal, da, db, ctx); | ||
decNumberReduce(&nlit->num_decimal, &nlit->num_decimal, ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we believe that the operation above (the add) is able to fit the result into our calculated digits then the reduce should not be needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After performing some tests I can tell that decNumberAdd
will function correctly with our digits calculation and the only thing we should do after is decNumberTrim
. We shouldn't call decNumberReduce
as it will convert the number to its minimal scientific form which is not desirable IMO:
Using reduce:
61e2 + 00009876543210000000e-2 => 9.87654321061E+13
Using trim:
61e2 + 00009876543210000000e-2 => 98765432106100
Not using either:
61e2 + 00009876543210000000e-2 => 98765432106100.00
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the decNumberReduce
was meant to address the trailing zero issue- I wasn't concerned about decNumberAdd
functioning properly. decNumberTrim
is the best option, I'll swap to that.
This is meant to be an example for how we might use decNumber to start implementing some arithmetic (and potentially some math functions, depending on what's available). It's not quite ready for merge- we should switch to using this in our constant folding code, and I still need to figure out what errors to look for on the context after the addition.
This adds a new
jv_number_add
function that adds two number jvs, consumes a reference for each of them, and returns a new number.I changed a couple small things about allocation of literal numbers:
decContextDefault
function to make sure we initialize the context properly (we had an error that used the wrong value for one of the fields- I'm not sure what the impact really was, though)decNumber
itself.