>> Hi folks, often times in science one expresses a value (say >> 1.03789291) and its error (say 0.00089) in a short way by parentheses >> like so: 1.0379(9) >> >> One can vary things a bit, but let's take the simplest case when we >> only keep 1 digit of the error (and round it of course) and round the >> value correspondingly. I've been searching around for a simple >> function that would take 2 float arguments and would return a string >> but didn't find anything although something tells me it's been done a >> gazillion times. >> >> What would be the simplest such function? > > Well, this basically works: > >>>> def format_error(value, error): > ... precision = int(math.floor(math.log(error, 10))) > ... format = "%%.%df(%%d)" % max(-precision, 0) > ... return format % (round(value, -precision), > ... int(round(error / 10 ** precision))) > ... >>>> format_error(1.03789291, 0.00089) > '1.0379(9)' > > Note that "math.floor(math.log(error, 10))" may return the wrong > decimal precision due to binary floating point rounding error, which > could produce some strange results: > >>>> format_error(10378929, 1000) > '10378900(10)' > > So you'll probably want to use decimals instead: > > def format_error(value, error): > value = decimal.Decimal(value) > error = decimal.Decimal(error) > value_scale = value.log10().to_integral(decimal.ROUND_FLOOR) > error_scale = error.log10().to_integral(decimal.ROUND_FLOOR) > precision = value_scale - error_scale > if error_scale > 0: > format = "%%.%dE" % max(precision, 0) > else: > format = "%%.%dG" % (max(precision, 0) + 1) > value_str = format % value.quantize(decimal.Decimal("10") ** > error_scale) > error_str = '(%d)' % error.scaleb(-error_scale).to_integral() > if 'E' in value_str: > index = value_str.index('E') > return value_str[:index] + error_str + value_str[index:] > else: > return value_str + error_str > >>>> format_error(1.03789291, 0.00089) > '1.0379(9)' >>>> format_error(103789291, 1000) > '1.03789(1)E+08' > > I haven't tested this thoroughly, so use at your own risk. :-)
Thanks a lot, this indeed mostly works, except for cases when the error needs to be rounded up and becomes two digits: >>> format_error( '1.34883', '0.0098' ) '1.349(10)' But in this case I'd like to see 1.35(1) Cheers, Daniel -- Psss, psss, put it down! - http://www.cafepress.com/putitdown -- http://mail.python.org/mailman/listinfo/python-list