#! /usr/bin/env python # Combining multiple (independent) ranges assuming log-normal distributions # Usage example: # combine.py 19..21 28..32 # # Copyright 2009 Sanjoy Mahajan. This is free software. # License: GNU GPLv3 (or any later version, at your option). from sys import argv, stderr, exit from math import log, exp, sqrt def help(): print '''Usage: %s [/]l1..u1 [/]l2..u2 ... A range preceded by a / means to divide, rather than multiply, by that range. A range with no .. is shorthand for N..N (a range with ratio 1). The output is the combined range in the form lower..midpoint..upper Examples: %s 1..2 1..2 => 1.22509..2..3.26505 %s => 1.22509..2..3.26505 %s 1..2 2..3 /3..4 => 0.652789..1..1.53189''' % ((argv[0],)*4) if len(argv) == 1 or argv[1] in ['-h', '--help']: help() exit() lower = upper = 1 log_width_squared = 0 for qty in argv[1:]: divide = False if qty[0] == '/': divide = True qty = qty[1:] numbers = [float(s) for s in qty.split('..')] if len(numbers) == 3: # ignore midpoint, if given l, u = numbers[0], numbers[2] elif len(numbers) == 1: # a sure value l, u = numbers[0], numbers[0] else: l, u = numbers if divide: l, u = 1/u, 1/l lower *= l upper *= u log_width_squared += log(u/l)**2 mean = sqrt(lower*upper) ratio = exp(0.5*sqrt(log_width_squared)) print "%g..%g..%g" % (mean/ratio, mean, mean*ratio)