Factorials and strange rounding errors #31

Closed
AJMiller opened this Issue Sep 17, 2012 · 3 comments

Comments

Projects
None yet
3 participants

Hi Dave,

Testing factorial math in our app, I noticed that the math parser is compiling factorials and introducing rounding errors unnecessarily. For example, the factorial of 12 is 479,001,600. If I run 12_11_10_9_8_7_6_5_4_3_2 through the math parser the result is correctly shown. If I run 12! through the parser it comes up with 479,001,599.9999997

I would normally chalk this up to doubles and computer rounding errors, but the parser is fully capable of parsing the actual factorial without any error as shown above. This leads me to suspect that the rounding error is occurring in how the parser figures out which numbers to multiply together. It is somehow figuring out the actual equation in a way that is introducing errors.

All of the above math has been run through the demo project with the same result.

davedelong was assigned Sep 17, 2012

Owner

davedelong commented Sep 17, 2012

This is likely the result of using the tgamma function for factorial. That enables DDMathParser to support non-integral factorials. Perhaps there should be a special case for factorializing positive integers?

Seems to occur with both negative and positive integers. I would gather that integer factorials would be the most common subset of factorials in general, no? Perhaps if the equation reduces down to an integer (positive or negative) it runs a simple loop?

horaceho commented Feb 7, 2013

As a temporary fix, I convert the result to an integral value (thus disable non-integral factorial):

NSNumber *result = [NSNumber numberWithDouble:tgamma([firstValue doubleValue]+1)];

NSDecimalNumber *decimal = [[NSDecimalNumber alloc] initWithDouble:result.doubleValue];
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                        scale:0
                                                                             raiseOnExactness:NO
                                                                              raiseOnOverflow:NO
                                                                             raiseOnUnderflow:NO
                                                                          raiseOnDivideByZero:NO];
NSDecimalNumber *rounded = [decimal decimalNumberByRoundingAccordingToBehavior:handler];
NSNumber *integerResult = [NSNumber numberWithDouble:rounded.doubleValue];

return [DDExpression numberExpressionWithNumber:integerResult];

davedelong closed this in 0438a26 Jan 4, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment