Skip to content

Instantly share code, notes, and snippets.

@andy-shev
Last active January 17, 2017 20:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andy-shev/708f0a514e674f08aa84cf8392da6e0a to your computer and use it in GitHub Desktop.
Save andy-shev/708f0a514e674f08aa84cf8392da6e0a to your computer and use it in GitHub Desktop.
Pack value with scale
#!/usr/bin/python -tt
# -*- coding: UTF-8 -*-
# vim: ts=4 sw=4 et ai si
from __future__ import print_function
import sys
import os
import math
"""
To find the difference with original algorithm
python pincfg.py 1000000 1 | sed -e '/Diff:/!d; /Diff: 0\//d'
where (1000000 - 1) is a maximum tested value.
"""
__author__ = "Andy Shevchenko"
__license__ = "GPL v2"
PROG = os.path.basename(sys.argv[0])
def usage():
sys.stdout.write("Usage %s [VALUE [USE_RANGE]]\n" % PROG)
TABLE = [
0, 1, 2, 3,
4095, 4096, 4097,
6141, 6144, 6147,
8187, 8192, 8197,
25000,
65533, 65534, 65535, 65536, 65537,
98323, 98324, 98325,
253789,
535444,
132382720,
135351252,
]
VMASK = 2**12 - 1
SSHIFT = 12
WIDTH = 16
def go(value, e, mask=VMASK, shift=SSHIFT, width=WIDTH):
#
# Original algorithm
#
sco = 0
argument = value
while argument > mask:
argument = (argument + 1) / 2
sco += 1
old = argument << sco
#
# While-loop-less algorithm
#
if value >> shift:
sc = int(math.log(value >> shift, 2)) + 1
else:
sc = 0
xv1 = xv2 = value
# Variant 1: round up
if sc and (value & ((1 << sc) - 1)):
xv1 += 1 << sc
nv1 = (xv1 >> sc) << sc
# Variant 2: closest
if sc and (value & (1 << (sc - 1))):
xv2 += 1 << sc
nv2 = (xv2 >> sc) << sc
# Initial values
xvs = "%*d / %-*d" % (e, xv1, e, xv2)
# Scale
scs = "%2d%s" % (sc, sc >= width and "*" or " ")
# New values
nvs = "%*d / %-*d" % (e, nv1, e, nv2)
# Difference
d1 = abs(old - nv1)
d2 = abs(old - nv2)
if d1 or d2:
ds = "Diff: %d/%-d" % (d1, d2)
else:
ds = ""
print("%-*d (%s) Scale: %s Result: %s => %*d %s" % (e, value, xvs, scs, nvs, e, old, ds))
def toint(value):
try:
return int(value)
except ValueError:
usage()
raise SystemExit("Invalid argument")
def toexp(value):
return value and int(math.ceil(math.log(value, 10))) or 1
def main(argv):
# Value
value = 0
table = True
if len(argv) > 1:
value = toint(argv[1])
table = False
# Range
rng = 0
if len(argv) > 2:
rng = toint(argv[2])
if table:
t = iter(TABLE)
e = toexp(max(TABLE))
else:
if rng:
t = range(0, value, rng)
else:
t = range(value, value + 1)
e = toexp(value)
for value in t:
go(value, e)
if __name__ == "__main__":
sys.exit(main(sys.argv))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment