code: def mpf_log(x, prec, rnd=round_fast):
      """
      Compute the natural logarithm of the mpf value x. If x is negative,
      ComplexResult is raised.
      """
      sign, man, exp, bc = x
      # ------------------------------------------------------------------
      # Handle special values
      if not man:
          if x == fzero:
              return fninf
          if x == finf:
              return finf
          if x == fnan:
              return fnan
      if sign:
          raise ComplexResult("logarithm of a negative number")
      wp = prec + 20
      # ------------------------------------------------------------------
      # Handle log(2^n) = log(n)*2.
      # Here we catch the only possible exact value, log(1) = 0
      if man == 1:
          if not exp:
              return fzero
          return from_man_exp(exp * ln2_fixed(wp), -wp, prec, rnd)
      mag = exp + bc
      abs_mag = abs(mag)
      # ------------------------------------------------------------------
      # Handle x = 1+eps, where log(x) ~ x. We need to check for
      # cancellation when moving to fixed-point math and compensate
      # by increasing the precision. Note that abs_mag in (0, 1) <=>
      # 0.5 < x < 2 and x != 1
      if abs_mag <= 1:
          # Calculate t = x-1 to measure distance from 1 in bits
          tsign = 1 - abs_mag
          if tsign:
              tman = (MPZ_ONE << bc) - man
          else:
              tman = man - (MPZ_ONE << (bc - 1))
          tbc = bitcount(tman)
          cancellation = bc - tbc
          if cancellation > wp:
              t = normalize(tsign, tman, abs_mag - bc, tbc, tbc, "n")
              return mpf_perturb(t, tsign, prec, rnd)
          else:
              wp += cancellation
          # TODO: if close enough to 1, we could use Taylor series
          # even in the AGM precision range, since the Taylor series
          # converges rapidly
      # ------------------------------------------------------------------
      # Another special case:
      # n*log(2) is a good enough approximation
      if abs_mag > 10000:
          if bitcount(abs_mag) > wp:
              return from_man_exp(exp * ln2_fixed(wp), -wp, prec, rnd)
      # ------------------------------------------------------------------
      # General case.
      # Perform argument reduction using log(x) = log(x*2^n) - n*log(2):
      # If we are in the Taylor precision range, choose magnitude 0 or 1.
      # If we are in the AGM precision range, choose magnitude -m for
      # some large m; benchmarking on one machine showed m = prec/20 to be
      # optimal between 1000 and 100,000 digits.
      if wp <= LOG_TAYLOR_PREC:
          m = log_taylor_cached(lshift(man, wp - bc), wp)
          if mag:
              m += mag * ln2_fixed(wp)
      else:
          optimal_mag = -wp // LOG_AGM_MAG_PREC_RATIO
          n = optimal_mag - mag
          x = mpf_shift(x, n)
          wp += -optimal_mag
          m = -log_agm(to_fixed(x, wp), wp)
          m -= n * ln2_fixed(wp)
      return from_man_exp(m, -wp, prec, rnd)
  
imports: import math
  from bisect import bisect
  from .backend import xrange
  from .backend import MPZ, MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_FIVE, BACKEND
  from .libmpf import round_floor, round_ceiling, round_down, round_up, round_nearest, round_fast, ComplexResult, bitcount, bctable, lshift, rshift, giant_steps, sqrt_fixed, from_int, to_int, from_man_exp, to_fixed, to_float, from_float, from_rational, normalize, fzero, fone, fnone, fhalf, finf, fninf, fnan, mpf_cmp, mpf_sign, mpf_abs, mpf_pos, mpf_neg, mpf_add, mpf_sub, mpf_mul, mpf_div, mpf_shift, mpf_rdiv_int, mpf_pow_int, mpf_sqrt, reciprocal_rnd, negative_rnd, mpf_perturb, isqrt_fast
  from .libintmath import ifib
label_desc: Use image node_id 26 for calling a global function with example usage: mpf_log(x, prec, rnd) and returns: from_man_exp, from_man_exp, fninf, finf, fnan, fzero, mpf_perturb, from_man_exp