1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

@EVAL's precision and significant digits

Discussion in 'Support' started by vefatica, Sep 4, 2017.

  1. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    The first result below is correct; the second is close but has fewer significant digits. The strings have 211 characters. I can't figure out what my precision specification has to do with the output.
    upload_2017-9-4_23-8-2.png
     
  2. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    For N<103, @EVAL[2**N] comes out right. The first precision spec that makes @EVAL[2**103] come out right is "0.11".
    Code:
    v:\> echo %@eval[2**103=0.10]
    10141204801825835211973625643010
    
    v:\> echo %@eval[2**103=0.11]
    10141204801825835211973625643008
    I can't figure out exactly how my precision spec is related to the output.
     
  3. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,854
    Likes Received:
    83
    It's the mapm m_apm_pow() function, specifically the second ("decimal_places") argument. If it's set to fewer characters than the result, you'll get rounding errors. (TCC is already adding 20 digits on its own, which is why you didn't see it until you got a > 30 digit result.)
     
  4. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    Maybe it's a bug, or a lack of documentation, (or me) but when computing base**exponent, (MAPM::pow() or m_apm_pow()) and base>1, "decimal_places" actually specifies the number of significant digits (which certainly includes what's to the left of the decimal point) and not the number of places after the decimal point.

    If you add the number below (instead of 20) to the desired number of decimal places (when base>1) you should be safe. If you wish, I'll translate it into the non-C++ version (i.e., using m_apm_func() instead of MAPM::func()).

    Code:
    // this is before the decimal point; add the desired number of decimal places
    INT extra (MAPM base, MAPM exponent)
    {
       MAPM u, mm1 = MM_One;
       INT x;
       u = ++((base.log10() * exponent).ceil());
       CHAR *szdp = (CHAR*) AllocMem(u.significant_digits()+1);
       u.toIntegerString(szdp);
       x = atoi(szdp);
       FreeMem(szdp);
       return x;
    }
    
    I reproduced (and fixed, as above) the problem with 2**103. But I don't need the fix for .5**(-103), which is the same number. @EVAL, however, has the same problem with both.
     
  5. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    ... or, more appropriately for @EVAL, the minimum of that number and 15,000.

    Another thing ... 10**10000 works, but 10**10001 evokes an overflow message. Does that reflect an older limit? Isn't it 15000 these days?
     
  6. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,854
    Likes Received:
    83
    10,000 digits to the left of the decimal, and 10,000 to the right. It is not 15,000.
     
  7. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    The help says
    And I was wrong about my .5**(-103) not needing the extra() digits. If you're going to use that, you should use it for any base.
     
  8. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    FWIW, extra() is a pretty tight estimate of what's needed. Below, extra is 46 when the number has 45 digits before the decimal point. I think there are special cases when extra()-1 won't be enough.
    Code:
    v:\> echo %@pow[1.01 10310.99]^r^n%_ruler
    extra = 46
    361111948879059149982803812474402661922976059.62768572890231244276
    ....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+....0....+....1...
     
  9. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    The change was in v19's "What's new".
     
  10. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    It needs absolute value of base.log10() (found out the hard way) :-)
    Code:
    INT extra (MAPM base, MAPM exponent)
    {
       MAPM mm1 = MM_One, u;
       INT x;
       u = ++(((base.log10()).abs() * exponent).ceil());
       CHAR *szdp = (CHAR*) AllocMem(u.significant_digits() + 1);
       u.toIntegerString(szdp);
       x = atoi(szdp);
       FreeMem(szdp);
       return x;
    }
    
    
     
  11. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,934
    Likes Received:
    30
    FWIW, this (below) is more than 20 times faster than extra() and should work in reasonable cases (intergalactic distances and the national debt being possible exceptions).
    Code:
        double   b = ... ,   // base
               e = ... ,   // exponent
               extra = 1 + ceil(e * abs(log10(b)));
    
     

Share This Page