Skip to content

math:sqrt and math:log could have wider domains #10504

@jpellegrini

Description

@jpellegrini

Currently, math:log and math:sqrt use the C functions log and sqrt. This is fine, but in the presence of bignums (as Erlang has), it becomes possible to wider their domains:

  1. $10^{2480}$ cannot be used as an argument to math:log, only because it is not representable as an IEEE double float. But it is representable as an Erlang bignum, and the result is an IEEE double float:
    $log(10^{2480})$ is close to $5710.411030625233$
    So it would perhaps be possible to make math:log accept larger numbers (a lot of them, since log grows, well, logarithmically :)

  2. $2^{2030}+111111111111111111111111117$ does not fit a double either. But similarly, it is an Erlang integer, and its square root does fit an IEEE double float (it is close to $3.511119404027961 \times 10^{305}$).

I'm not saying, of course, that getting this to work is "easy". Anyway, here's a survey on how many different Scheme implementations deal with it in different ways (but no implementation details here):

https://github.com/schemedoc/surveys/blob/master/surveys/log-requires-floating-point.md

And I can explain how STklos Scheme gets it done (because I have implemented these two enhancements):

  1. STkloslog of bignums is very simple, but it uses the GMP (I know Erlang doesn't):
static double my_bignum_log(SCM z) {
  /* The GMP function mpz_get_d_2exp is similar to the C library
     function frexp: it returns a float D between 0.5 and 1.0,
     and sets an exponent E. Then,
     N = D * 2^E
     is the (possibly truncated) value of the original number.
     Then calculating the log is simple:

     log(N) = log(D*2^E)
            = log(D) + log(2^E)
            = log(D) + log(2) * E                               */
  long   expo;
  double d = mpz_get_d_2exp(&expo, BIGNUM_VAL(z));
  return log(d) + log(2) * (double) expo;
}

But since Erlang has its own bignum implementation, maybe it won't be hard to get this working (?)

  1. STklos sqrt tries a couple of methods (like identifying perfect squares etc), and when all fail, it uses Newton's method. It is slow (because it is computed using bignum rationals), but we get some more answers for the function.
    /* Ok, we tried everything. There's only the slow path now! */
    SCM x = x0;
    SCM x_new = x0;
    SCM err = x0;

    /* Approximate the square root... Essentially, Newton's method,
       but coded using STklos' internal sub2, div2, mul2, abs
       functions.  */
    while(STk_numgt2(err, rational_epsilon) > 0 &&
          isfinite(REAL_VAL(exact2inexact(x_new)))) {
        x_new = sub2(x, div2(sub2(mul2(x, x), z),
                             mul2(x, MAKE_INT(2))));
        err = STk_abs(sub2(x_new, x));
        x = x_new;
    }
    /* Return inexact, because if we got here, the square of this
       result will not equal to z (it's an approximation, so it would
       be strange to give an "exact" result that is not "exactly" the
       result of the operation). But for floating-point, it is
       acceptable to offer an approximation.  */
    return exact2inexact(x_new);

Here mul2, div2, sub2 are generic 2-argument functions, and x is a bignum (so the computation is fully rational until the last moment, when exact2inexact converts it to a double).

Also,

    SCM x = x0;

Here, x0 is computed earlier using mpz_sqrt, so it is the truncated square root.

For reference, the math code for STklos (the C part) is here:

https://github.com/egallesio/STklos/blob/master/src/number.c

By no means I believe Erlang "needs" this -- I see it as a low-priority enhancement; and I also wouldn't say that my implementation for STklos makes sense for Erlang... Just wanted to share, in case the Erlang implementors find it to be useful.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions