def run(self, xrange="log", diff="relative"): r""" Compare accuracy of different methods for computing f. *xrange* is:: log: [10^-3,10^5] logq: [10^-4, 10^1] linear: [1,1000] zoom: [1000,1010] neg: [-100,100] *diff* is "relative", "absolute" or "none" *x_bits* is the precision with which the x values are specified. The default 23 should reproduce the equivalent of a single precisio """ linear = not xrange.startswith("log") if xrange == "zoom": lin_min, lin_max, lin_steps = 1000, 1010, 2000 elif xrange == "neg": lin_min, lin_max, lin_steps = -100.1, 100.1, 2000 elif xrange == "linear": lin_min, lin_max, lin_steps = 1, 1000, 2000 lin_min, lin_max, lin_steps = 0.001, 2, 2000 elif xrange == "log": log_min, log_max, log_steps = -3, 5, 400 elif xrange == "logq": log_min, log_max, log_steps = -4, 1, 400 else: raise ValueError("unknown range "+xrange) with mp.workprec(500): # Note: we make sure that we are comparing apples to apples... # The x points are set using single precision so that we are # examining the accuracy of the transformation from x to f(x) # rather than x to f(nearest(x)) where nearest(x) is the nearest # value to x in the given precision. if linear: lin_min = max(lin_min, self.limits[0]) lin_max = min(lin_max, self.limits[1]) qrf = np.linspace(lin_min, lin_max, lin_steps, dtype='single') #qrf = np.linspace(lin_min, lin_max, lin_steps, dtype='double') qr = [mp.mpf(float(v)) for v in qrf] #qr = mp.linspace(lin_min, lin_max, lin_steps) else: log_min = np.log10(max(10**log_min, self.limits[0])) log_max = np.log10(min(10**log_max, self.limits[1])) qrf = np.logspace(log_min, log_max, log_steps, dtype='single') #qrf = np.logspace(log_min, log_max, log_steps, dtype='double') qr = [mp.mpf(float(v)) for v in qrf] #qr = [10**v for v in mp.linspace(log_min, log_max, log_steps)] target = self.call_mpmath(qr, bits=500) pylab.subplot(121) self.compare(qr, 'single', target, linear, diff) pylab.legend(loc='best') pylab.subplot(122) self.compare(qr, 'double', target, linear, diff) pylab.legend(loc='best') pylab.suptitle(self.name + " compared to 500-bit mpmath")
def ieee_eval(x): """ Return the string representation of a floating point value in each prec. """ x = mpf(x) sreps = list() for prec in ieee_formats: with mp.workprec(prec): sreps.append(str(x)) return sreps
def workfloat(bytes_or_bits): ok = False bytes_or_bits = int(bytes_or_bits) for fmt in ieee_formats.values(): if bytes_or_bits in (fmt.bits, fmt.bits // 8): ok = True with mp.workprec(fmt.prec): yield if not ok: raise KeyError(bytes_or_bits)
def dist(self, f1, f2): """ Return the distance between two values in ULPs. """ with mp.workprec(self.prec): lo = mpf(min(f1, f2)) hi = mpf(max(f1, f2)) dist = 0 while lo != hi: lo += self.ulp(lo) dist += 1 return dist
def ulp(self, x): """ Return the unit of least precision for a value x. This is the floating point value which represents the delta between x and the closest representible number. """ from .util import zero, one, two x = mpf(x) n = 0 min_exp = abs(self.min_exp(denorm=True)) with mp.workprec(self.prec): ulp = next_power(x) while (x + ulp) != x and ulp != zero and n < min_exp: ulp /= two n += 1 return ulp * two
def call_mpmath(self, vec, bits=500): """ Direct calculation using mpmath extended precision library. """ with mp.workprec(bits): return [self.mp_function(mp.mpf(x)) for x in vec]
def mp_fn(vec, bits=500): """ Direct calculation using sympy multiprecision library. """ with mp.workprec(bits): return [_mp_fn(mp.mpf(x)) for x in vec]