Short pieces

Since this is a short month, here are some short pieces of code.

A far shorter number naming and approximating function than the previous post – clearly has far less options.

 

from math import log
def approx(n):
    """48593829509385 -> '48.593 trillion'
    if n is a string, that is taken as a power of 1000
    From Orthallelous
    follows the naming scheme given by Landon Curt Noll
    http://www.isthe.com/chongo/tech/math/number/number.html"""
    d=r='';i=0
    u=['thousand','m','b','tr','quadr','quint','sext','sept','oct','non','dec']
    o=['','un','duo','tre','quattuor','quin','sex','septen','octo','novem','dec']
    t=['','dec','vigin','trigin','quadragin','quinquagin','sexagin','septuagin','octogin','nonagin']
    h=['','cen','duocen','trecen','quadringen','quingen','sescen','septingen','octingen','nongen']
    def q(k):return''.join([h[(k//100)%10],o[k%10],t[(k//10)%10]])
    if not n:return'0'
    elif type(n)==str:c=int(n)-1;a=1
    else:
        if n<0:d='-';n=abs(n)
        c=int(round(log(n,1000),7))-1;a=(n//1000**(c))/1000.
    s=('illion'if 20>(c%100)>9 or c<11 else'tillion')if c else''
    if c<0:return d+str(n)
    elif c<=10:r=u[c]
    else:
        while c:
            c,p=divmod(c,1000)
            r=''.join([q(p),('millia'*i if p else''),r]);i+=1
        if r[:2]==q(1)and i>1:r=r[2:]
    return''.join([d,'{:.3f} '.format(a),r,s])

Examples:

>>> approx(4859)
'4.859 thousand'
>>> approx(56)
'56'
>>> approx(1000230928345)
'1.000 trillion'
>>> approx(99887766554433221100)
'99.887 quintillion'
>>> approx('1002003')
'1.000 milliamilliaduomilliaduotillion'

 

 
—————-
Here’s a different approximator, uses SI prefixes. Will return a string such that you can append a unit to it without additional formatting. I am using a ‘u’ instead of a ‘µ’ though. if you want the µ, change the ‘u’ at the end of the 4th line to ‘\xb5’, but this is dependent on your encoding.

from math import log, floor
def si(val):
    "Approximates n with SI prefixes\nFrom Orthallelous"
    SI={-8:'y',-7:'z',-6:'a',-5:'f',-4:'p',-3:'n',-2:'u',
    -1:'m',1:'k',2:'M',3:'G',4:'T',5:'P',6:'E',7:'Z',8:'Y'}
    p=int(floor(log(abs(val),1e3)))
    if not p:return str(val)+' '
    if abs(p)>8:p=p//abs(p)*8
    a=(val//1e3**(p-1))/1e3
    return'{:.2f} {}'.format(a,SI[p])

Examples:

>>> si(45)
'45 '
>>> si(348642121)
'348.64 M'
>>> si(0.00000000456)
'4.56 n'
>>> si(938272046)+'eV'
'938.27 MeV'
>>> si(632.8e-9)+'m'
'632.80 nm'

 

And here’s the reverse!

def rsi(val, unit=None):
    "Converts an SI value to a float\nFrom Orthallelous"
    SI={'y':-8,'z':-7,'a':-6,'f':-5,'p':-4,'n':-3,'u':-2,'\xb5':-2,
   'm':-1,'k':1,'M':2,'G':3,'T':4,'P':5,'E':6,'Z':7,'Y':8}
    if unit:val=val.replace(unit,'',1)
    for i in SI.keys():
        if i in val:n=1e3**SI[i];val=val.replace(i,'');break
    else:n=1.
    return n*float(val)

Examples:

>>> rsi('632.80 nm','m')
6.328e-07
>>> rsi('938.27 MeV', 'eV')
938270000.0
>>> rsi('500.7 k')
500700.0
>>> rsi('25.4 mm', 'm')
0.0254

 
 
—————-
A slightly different DeltaT from here – now has a style option. If st is 0, you’ll get the time written out. If st is 1, you’ll get an abbreviated form of the written format. If st is -1, then you’ll get a digital clock like form.

def DeltaT(sec,st=0):
    "75 -> '1 minute, 15 seconds'\nfrom Orthallelous"
    if sec==0:return'no elasped time'
    S,Q,c,t=[],abs(sec),0,''
    N=['second','minute','hour','day','week']
    for j in[60,60,24,7]:Q,r=divmod(Q,j);S.append(r)
    S.append(Q)
    if st<0:
        S.reverse();S=[int(i)for i in S]
        t=':'.join(list(map('{:02d}'.format,S)))
        while len(t)>8 and t[0]in'0:':t=t[1:]
        return t
    for T in S:
        if T==0:c+=1;continue
        v=str(int(T))
        if c==0 and int(T)!=T:v=str(round(T,2))
        n=N[c];c+=1
        if T!=1 and not st:n=''.join([n,'s'])
        if st:t=''.join([v,n[0],' ',t])
        else:t=''.join([v,' ',n,', ',t])
    return t.rstrip(', ')

Examples:

>>> DeltaT(3727)
'1 hour, 2 minutes, 7 seconds'
>>> DeltaT(3727, 1)
'1h 2m 7s'
>>> DeltaT(3727, -1)
'01:02:07'

 
 
—————-
And here’s a linear interpolater. Pass it two vectors and it’ll add points between them. Will return a list of tuples; does not return the end point – change the +1 in the “for i in range(n+1):” line to n+2 if you want the endpoint.

def lerp(v1, v2, numPts=10):
    "linearly interpolate from v1 to v2\nFrom Orthallelous"
    if len(v1)!=len(v2):raise ValueError("different dimensions")
    D,V,n=[],[],abs(numPts)
    for i,u in enumerate(v1):D.append(v2[i]-u)
    for i in range(n+1):
        vn=[]
        for j,u in enumerate(v1):vn.append(u+D[j]/float(n+1)*i)
        V.append(tuple(vn))
    return V

Examples:

>>> lerp( (5,) , (7,) , 7)#one dimensional vectors
[(5.0,), (5.25,), (5.5,), (5.75,), (6.0,), (6.25,), (6.5,), (6.75,)]
>>> lerp( (255,0,0), (0,0,255), 3)#red to green
[(255.0, 0.0, 0.0), (191.25, 0.0, 63.75), (127.5, 0.0, 127.5), (63.75, 0.0, 191.25)]
Posted in Python

Leave a comment

In Archive
Design a site like this with WordPress.com
Get started