Skip to content
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

precision of ln and pow #130

Closed
tonyofbyteball opened this issue May 17, 2019 · 3 comments
Closed

precision of ln and pow #130

tonyofbyteball opened this issue May 17, 2019 · 3 comments

Comments

@tonyofbyteball
Copy link

From ln documentation:

Internally, this method is dependent on a constant whose value is the natural logarithm of 10. This LN10 variable in the source code currently has a precision of 1025 digits, meaning that this method can accurately calculate up to 1000 digits.

If more than 1000 digits is required then the precision of LN10 will need to be increased to 25 digits more than is required - though, as the time-taken by this method increases exponentially with increasing digits, it is unlikely to be viable to calculate over 1000 digits anyway.

What's the special significance of the number 25? Is it the number of rounding digits? can it be changed?

From pow documentation:

The return value may, depending on the rounding mode, be incorrectly rounded only if the first 15 rounding digits are 15 zeros (and there are non-zero digits following at some point), or 15 nines, or a 5 or 4 followed by 14 nines.

Again, what's special about 15?

Therefore, assuming the first 15 rounding digits are each equally likely to be any digit, 0-9, the probability of an incorrectly rounded result is less than 1 in 250,000,000,000,000.

When working with user-entered data, an attacker may try to supply problematic numbers on purpose. It would be great to control precision to avoid that.

@MikeMcl
Copy link
Owner

MikeMcl commented May 18, 2019

What's the special significance of the number 25?

The number has no special significance.

Is it the number of rounding digits?

Extra digits in the LN10 constant are necessary to calculate rounding digits.

can it be changed?

The LN10 constant can be changed in the source file, yes. The library will throw an error if there are not enough LN10 digits to calculate and correctly round the natural logarithm function at a given precision.

Again, what's special about 15?

That is the number of rounding digits that the power function calculates. That cannot be changed.

When working with user-entered data, an attacker may try to supply problematic numbers on purpose. It would be great to control precision to avoid that.

Precision can be controlled. The number of rounding digits is an internal matter. If a result of the power operation is incorrectly rounded the maximum error will be 1 ULP (unit in the last place), which is not likely to help anybody attack anything.

A user can calculate as many rounding digits as they like anyway, by just calculating pow to a higher precision and then rounding the result themselves.

@tonyofbyteball
Copy link
Author

Thanks for the answers. I understand that these numbers are arbitrarily chosen and that the probability of incorrect (up to 1 ulp) rounding is very small because it is unlikely to have 4 and 14 9s or 5 and 14 0s as rounding digits.

To clarify what attack vector I'm concerned about, it is possible that another implementation calculates the same function with always correct rounding, or with more accurate rounding (e.g. by using 20 rounding digits instead of 15), and arrives at a different result. Even though the difference is only 1 ulp, this can lead to consensus failure in distributed systems. One example of such distributed systems is cryptocurrency platforms where all calculations are supposed to be performed by multiple independent nodes working on different hardware and software and using different implementations of the same protocol.

On another, but related, matter, in naturalExponential implementation:

        if (rep < 3 && checkRoundingDigits(sum.d, wpr - guard, rm, rep)) {
          Ctor.precision = wpr += 10;
          denominator = pow = t = new Ctor(1);
          i = 0;
          rep++;
        } else {

I'm not sure why precision is expanded only up to 3 times (if (rep < 3 ....). It seems to limit the number of rounding digits by 30. Since it is exp and the input precision is limited, it seems the result should be non-terminating and there is no chance to get an infinite sequence of 0s or 9s.

@MikeMcl
Copy link
Owner

MikeMcl commented May 19, 2019

I'm not sure why precision is expanded only up to 3 times...

Yes, I was wondering about that yesterday when I looked over the code before responding to this issue. I can't remember exactly why I did that.

I notice the code has been changed in a more recent unpublished version of decimal.js that I have been working on in response to #97.

decimal.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants