language/units: do not quantize

This commit is contained in:
Sebastien Bourdeauducq 2014-08-13 17:52:01 +08:00
parent 98b23eadf8
commit a2691ab07a
1 changed files with 45 additions and 23 deletions

View File

@ -1,30 +1,53 @@
from collections import namedtuple from collections import namedtuple
from fractions import Fraction
_prefixes_str = "pnum_kM" _prefixes_str = "pnum_kMG"
_smallest_prefix = Fraction(1, 10**12)
Unit = namedtuple("Unit", "base_prefix name") Unit = namedtuple("Unit", "name")
class DimensionError(Exception): class DimensionError(Exception):
pass pass
class Quantity: class Quantity:
def __init__(self, amount, unit): def __init__(self, amount, unit):
self.amount = int(amount) self.amount = amount
self.unit = unit self.unit = unit
def __repr__(self): def __repr__(self):
r_amount = self.amount r_amount = self.amount
r_prefix = self.unit.base_prefix if isinstance(r_amount, int) or isinstance(r_amount, Fraction):
if r_amount: r_prefix = 0
while not r_amount % 1000 and r_prefix < len(_prefixes_str): r_amount = r_amount/_smallest_prefix
r_amount //= 1000 if r_amount:
r_prefix += 1 numerator = r_amount.numerator
return str(r_amount) + " " + _prefixes_str[r_prefix] + self.unit.name while numerator % 1000 == 0 and r_prefix < len(_prefixes_str):
numerator /= 1000
r_amount /= 1000
r_prefix += 1
prefix_str = _prefixes_str[r_prefix]
if prefix_str == "_":
prefix_str = ""
return str(r_amount) + " " + prefix_str + self.unit.name
else:
return str(r_amount) + " " + self.unit.name
def __rmul__(self, other): def __mul__(self, other):
if isinstance(other, Quantity): if isinstance(other, Quantity):
return NotImplemented return NotImplemented
return Quantity(self.amount*other, self.unit) return Quantity(self.amount*other, self.unit)
def __rmul__(self, other):
if isinstance(other, Quantity):
return NotImplemented
return Quantity(other*self.amount, self.unit)
def __truediv__(self, other):
if isinstance(other, Quantity):
return NotImplemented
return Quantity(self.amount/other, self.unit)
def __floordiv__(self, other):
if isinstance(other, Quantity):
return NotImplemented
return Quantity(self.amount//other, self.unit)
def __neg__(self): def __neg__(self):
return Quantity(-self.amount, self.unit) return Quantity(-self.amount, self.unit)
@ -76,17 +99,16 @@ def check_unit(value, unit):
raise DimensionError raise DimensionError
return value.amount return value.amount
def _register_unit(base_prefix, name, prefixes): def _register_unit(name, prefixes):
base_prefix_exp = _prefixes_str.index(base_prefix) unit = Unit(name)
unit = Unit(base_prefix_exp, name) globals()[name+"_unit"] = unit
globals()["base_"+name+"_unit"] = unit amount = _smallest_prefix
for prefix in prefixes: for prefix in _prefixes_str:
prefix_exp = _prefixes_str.index(prefix) if prefix in prefixes:
exp_d = prefix_exp - base_prefix_exp quantity = Quantity(amount, unit)
assert(exp_d >= 0) full_name = prefix + name if prefix != "_" else name
quantity = Quantity(1000**exp_d, unit) globals()[full_name] = quantity
full_name = prefix + name if prefix != "_" else name amount *= 1000
globals()[full_name] = quantity
_register_unit("p", "s", "pnum_") _register_unit("s", "pnum_")
_register_unit("_", "Hz", "_kM") _register_unit("Hz", "_kMG")