def frexp(x): """ Version of frexp that works for numbers with uncertainty, and also for regular numbers. """ # The code below is inspired by uncert_core.wrap(). It is # simpler because only 1 argument is given, and there is no # delegation to other functions involved (as for __mul__, etc.). aff_func = to_affine_scalar(x) if aff_func._linear_part: (mantissa, exponent) = math.frexp(aff_func.nominal_value) return ( AffineScalarFunc( mantissa, # With frexp(x) = (m, e), x = m*2**e, so m = x*2**-e # and therefore dm/dx = 2**-e (as e in an integer that # does not vary when x changes): LinearCombination([2**-exponent, aff_func._linear_part])), # The exponent is an integer and is supposed to be # continuous (errors must be small): exponent) else: # This function was not called with an AffineScalarFunc # argument: there is no need to return numbers with uncertainties: return math.frexp(x)
def ldexp(x, i): # Another approach would be to add an additional argument to # uncert_core.wrap() so that some arguments are automatically # considered as constants. aff_func = to_affine_scalar(x) # y must be an integer, for math.ldexp if aff_func._linear_part: return AffineScalarFunc( math.ldexp(aff_func.nominal_value, i), LinearCombination([(2**i, aff_func._linear_part)])) else: # This function was not called with an AffineScalarFunc # argument: there is no need to return numbers with uncertainties: # aff_func.nominal_value is not passed instead of x, because # we do not have to care about the type of the return value of # math.ldexp, this way (aff_func.nominal_value might be the # value of x coerced to a difference type [int->float, for # instance]): return math.ldexp(x, i)