ruby/ruby — pull request #332 by GarthSnyder (2013-06-18 23:01:51+00:00)
Title: Fix BigMath::exp for negative immediate types, add tests for these cases

Please note: I'm not 100% sure that this fix is the correct fix, so this patch requires careful scrutiny by someone familiar with the BigDecimal implementation. However, the test cases I added do show a clear problem with BigMath.exp of immediate types with values < 0 and may be useful to integrate regardless of whether the fix goes in.

Problem: BigMath.exp(-x, n) == BigMath.exp(x, n) whenever x is an immediate type. For example, BigMath.exp(-1, 20) is 2.718. The correct value is 0.3679 (that is, 1/2.718)

Mechanism: It appears that the VALUE x passed into BigMath_s_exp is promoted to a Real *vx. At bigdecimal.c:2742, the code flips the sign bit on negative values as part of the implementation of the identity that E ** -x == 1 / (E ** x). Later at line 2774, the sign is rechecked and the reciprocal of the result is returned if the original argument was negative.

However, in the calculation loop at line 2765, it's the original VALUE x that's used in the iteration instead of vx->obj. This works OK for BigDecimals since VPSetSign reaches though vx into the original x. (That is itself a separate problem, since it results in the argument being unexpectedly modified; I will submit a separate issue for that.) But immediate types still have their original (negative) values.

Fix: I suspect that it's just ToValue(vx) that's intended here instead of x.