Skip to content

math.log(x, 10) gives different result than math.log10(x) #47974

Description

@segfaulthunter
BPO 3724
Nosy @rhettinger, @terryjreedy, @mdickinson, @vstinner
Files
  • log.patch: Internally use math.log10 when math.log gets the base 10 to improve accuracy and performance.
  • math_doc.patch: Documentation tweak.
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/mdickinson'
    closed_at = <Date 2008-12-05.21:47:35.319>
    created_at = <Date 2008-08-29.12:32:07.135>
    labels = ['type-bug']
    title = 'math.log(x, 10) gives different result than math.log10(x)'
    updated_at = <Date 2009-09-01.09:58:50.177>
    user = 'https://bugs.python.org/segfaulthunter'

    bugs.python.org fields:

    activity = <Date 2009-09-01.09:58:50.177>
    actor = 'terry.reedy'
    assignee = 'mark.dickinson'
    closed = True
    closed_date = <Date 2008-12-05.21:47:35.319>
    closer = 'mark.dickinson'
    components = []
    creation = <Date 2008-08-29.12:32:07.135>
    creator = 'segfaulthunter'
    dependencies = []
    files = ['11310', '11362']
    hgrepos = []
    issue_num = 3724
    keywords = ['patch']
    message_count = 12.0
    messages = ['72129', '72389', '72398', '72423', '74349', '74578', '74584', '74630', '74734', '74738', '77077', '92139']
    nosy_count = 5.0
    nosy_names = ['rhettinger', 'terry.reedy', 'mark.dickinson', 'vstinner', 'segfaulthunter']
    pr_nums = []
    priority = 'normal'
    resolution = 'rejected'
    stage = None
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue3724'
    versions = ['Python 2.6']

    Activity

    1. segfaulthunter commented on Aug 29, 2008

      segfaulthuntermannequin
      MannequinAuthor

      I have found out that the result of math.log(x, 10) is slightly more
      inaccurate than the one of math.log10(x). Probably the best example is
      math.log(1000, 10) and math.log10(1000). I have attached a patch that
      forces math.log to internally use log10 when it gets the base 10. Patch
      is against revision 66056. Also adds 3 tests to test_math.py to test new
      behaviour implemented.

    2. mdickinson commented on Sep 3, 2008

      @mdickinson
      Member

      I can't really see a compelling reason to make this change---it
      seems like an unnecessary complication to add to what's currently
      a simple function. Someone who really needs the accuracy can
      just use log10. Perhaps a note in the documentation for log
      suggesting this would be useful.

      I guess this solution seems insufficiently general: why 'fix'
      log(x, 10) but not log(x, 2), for example?

      OTOH, a two-argument log that was guaranteed correctly rounded
      (or accurate to within 1ulp) for *all* bases would certainly
      be of interest! But that's a fairly major project...

    3. rhettinger commented on Sep 3, 2008

      @rhettinger
      Contributor

      Mark, thanks for the first review comments. Am also disturbed by the
      lack of generality and don't think it wise to introduce a discontinuity.
      Am rejecting this patch. Leaving the bug report open in case other
      solutions arise.

    4. segfaulthunter commented on Sep 3, 2008

      segfaulthuntermannequin
      MannequinAuthor

      Uploaded small documentation patch warning the user of math.log(x, 10)
      inaccuracy.

    5. rhettinger commented on Oct 5, 2008

      @rhettinger
      Contributor

      Mark, is some of the inaccuracy due to double rounding? Could we make
      the two argument form more accurate by allowing the compiler to generate
      code that uses full internal precision, log(n)/log(d), instead of
      prematurely forcing the intermediate results to a PyFloat?

    6. mdickinson commented on Oct 9, 2008

      @mdickinson
      Member

      Mark, is some of the inaccuracy due to double rounding?

      No, I don't think so; at least, not in the sense of rounding the same
      value twice (with different precisions). I get similar results on my
      Core 2 Duo machine, which should be immune to x87 style problems
      (because Apple's gcc turns sse instructions on by default, I guess).
      It's just a result of three separate rounds: one for each log, and one
      for the result of the division.

      Could we make the two argument form more accurate by allowing the
      compiler to generate code that uses full internal precision,
      log(n)/log(d), instead of prematurely forcing the intermediate results
      to a PyFloat?

      Seems to me that would only work on older x86 hardware, unless we
      deliberately use long double in place of double for the intermediate
      results.

      Personally, I don't think it's worth the effort of fixing this: the
      result of log(x, 10) is accurate to within a few ulps anyway, which
      should be plenty good enough for any well-coded numerical work: any
      numerically aware programmer should be well aware that it's dangerous to
      rely on floating-point operations giving exact results.

      And in any case there's always log10.

      As a separate issue, it may be worth exposing C99's log2 function in
      some future version of Python. This, presumably, can be relied upon
      always to give exact results for powers of 2, which could be useful in
      some applications.

    7. rhettinger commented on Oct 9, 2008

      @rhettinger
      Contributor

      +1 on a log2 function, especially one that has been generalized to work
      with long integers. It would help with the "numbits" problem that
      comes-up all the time.

    8. vstinner commented on Oct 10, 2008

      @vstinner
      Member

      About large integers which can not be converted to float (too big!):
      it would be nice if math.log2() and/or math.log10() works which such
      numbers. But it would better if you know if the functions used the FPU
      or not (only integers). Idea:

      • logX(int)->int: don't use FPU
      • logX(float)->float: use FPU
      • logX(int)->float: use FPU

      What should be the default type for logX(int)? People expects float
      when using logX().

      Note: logX() means math.log(), math.log2() and/or math.log10().

    9. mdickinson commented on Oct 14, 2008

      @mdickinson
      Member

      Note that log2(int) -> float wouldn't entirely replace
      numbits, due to loss of precision in the result.

      e.g. log2(2**100), log2(2**100+1) and log2(2**100-1) would likely all
      return exactly the same result (100.0), where numbits wants results of
      101, 101 and 100 respectively.

    10. vstinner commented on Oct 14, 2008

      @vstinner
      Member

      About the number of bits: I prefer an the implementation in int/long
      types proposed in issue bpo-3439.

    11. mdickinson commented on Dec 5, 2008

      @mdickinson
      Member

      I'm closing this, for reasons already given.

      For the proposal to add log2, see bpo-3366.

    12. terryjreedy commented on Sep 1, 2009

      @terryjreedy
      Member

      The docs were patched in r74617 to (re)close bpo-6765.
      This included something similar to the OP's math_doc.patch.

    13. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions