Skip to content

Instantly share code, notes, and snippets.

@WeatherGod
Created January 6, 2016 18:08
Show Gist options
  • Save WeatherGod/272f4022bf7a8ca12ff4 to your computer and use it in GitHub Desktop.
Save WeatherGod/272f4022bf7a8ca12ff4 to your computer and use it in GitHub Desktop.
Common Sigs attempt
import numpy as np
import math
def CalcOffset(a, oom) :
if np.isinf(oom) :
return np.nan
minval = a.min()
if minval < 0.0 :
big_offset = math.ceil(minval/10**oom)*10**oom
else :
big_offset = math.floor(minval/10**oom)*10**oom
# We want the smallest possible OoM, so subtract the big offset
# so that we have a set of value differences. This will help
# in identifying situations like '[15.99, 16.01]' because the
# data difference has no common OoM.
# Meanwhile, '[12331.4, 12350.5]' will find 12300 as the final
# offset.
diff_oom = common_sigdigs(a - big_offset)
# If subtracting the big offset resulted in values that did not
# have the same OoM, then the big offset is the offset we want.
if np.isinf(diff_oom) :
diff_oom = oom
# I want to use math.trunc(), but there seems to be a difference in domain
# for it and for math.ceil() and math.floor()...
if a.min() < 0.0 :
return math.ceil(a.min()/10**diff_oom)*10**diff_oom
else :
return math.floor(a.min()/10**diff_oom)*10**diff_oom
def common_sigdigs(a) :
# Absolute value to allow zero-crossing
a = np.abs(np.asanyarray(a))
valmax = a.max()
valmin = a.min()
if valmin == valmax :
# Same absolute values, so same sig digs, so return 0.0
return 0.0
# Avoid log10 domain error
if valmin > 0.0 :
if math.floor(math.log10(valmax)) == math.floor(math.log10(valmin)) :
return math.ceil(math.log10(valmax - valmin))
else :
# Assume that 0.0 has an OoM of 0.
if math.floor(math.log10(valmax)) == 0.0 :
return 0.0
# If they aren't of the same OoM, then return -inf so that
# a calculated offset will be zero.
return -np.inf
def CalcOffset_brute(a) :
if len(a) == 0 :
return np.nan
comp_str = "%25.10f" % abs(a[0])
a_str = [("%25.10f" % abs(b)) for b in a[1:]]
decpoint_loc = comp_str.find('.')
if decpoint_loc == -1 :
decpoint_loc = len(comp_str)
index = 0
while index < len(comp_str) :
if any((b[index] != comp_str[index]) for b in a_str) :
break
index += 1
try :
val = math.copysign(float(comp_str[:index]), min(a))
if comp_str[:index].find('.') == -1 :
val *= 10**(decpoint_loc - index)
return val if val != 0.0 else np.nan
except :
return np.nan
if __name__ == '__main__' :
testdata = ([ 0.4538, 0.4559, 0.4553, 0.4578],
[ 3789.12, 3782.89, 3783.1 ],
[ 45124.3, 45831.34, 45831.75],
[ 0.000721, 0.0007283, 0.0007243],
[ 12592.82, 12599.1, 12593.5, 12591.43],
[ 9., 10., 11., 12.],
[ 900., 1000., 1100., 1200.],
[ 1900., 1000., 1100., 1200.],
[ 0.99, 1.01],
[ 9.99, 10.01],
[ 99.99, 100.01],
[ 5.99, 6.01],
[ 15.99, 16.01],
[-0.452, -0.4, 0.411, 0.492],
[-0.492, -0.452, 0.411, 0.4, 0.492],
[12331.4, 12394.102, 12350.5],
[-12335.3, -12310.4, 12310.2, 12335.3])
for a in testdata :
a = np.array(a)
common_oom = common_sigdigs(a)
offset = CalcOffset(a, common_oom)
offset_brute = CalcOffset_brute(a)
ismatch = ((offset == offset_brute) or (np.isnan(offset) and
np.isnan(offset_brute)))
print a, '\t', common_oom, offset, offset_brute, \
('PASS' if ismatch else 'FAIL')
if np.isfinite(offset) :
print a - offset
common_oom = common_sigdigs(-a)
offset = CalcOffset(-a, common_oom)
offset_brute = CalcOffset_brute(-a)
ismatch = ((offset == offset_brute) or (np.isnan(offset) and
np.isnan(offset_brute)))
print -a, '\t', common_oom, offset, offset_brute, \
('PASS' if ismatch else 'FAIL')
if np.isfinite(offset) :
print (-a) - offset
print ' '
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment