This gonna be my first question here. I am trying to make a decimal.Decimal child class which mainly differs the parent by making autonormalization on itself and on the results of its callable arguments whose returns Decimal objects. The code below have the concept to
decorate all methods of Decimal to return MyDecimal instances (whose trim zeros of the end of their strings by creation) instead of decimal.Decimals. For this, metaclass was used.
However, I feel this code a bit hacky though. Moreover, according to the speed test results, it is also damn slow: 2.5 secs for the decimal.Decimal vs. 16 secs for MyDecimal on my system.
My question is: Is there a cleaner (and faster) way of doing this?
import decimal
class AutoNormalizedDecimal(type):
def __new__(cls, name, bases, local):
local_items = list(local.items())
parent_items = [i for i in bases[0].__dict__.items()
if i[0] not in local.keys()]
for a in local_items + parent_items:
attr_name, attr_value = a[0], a[1]
if callable(attr_value):
local[attr_name] = cls.decorator(attr_value)
return super(AutoNormalizedDecimal, cls).__new__(
cls, name, bases, local)
#classmethod
def decorator(cls, func):
def wrapper_for_new(*args, **kwargs):
new_string = args[1].rstrip('0').rstrip('.')
if not new_string:
new_string = '0'
newargs = (args[0], new_string)
return func(*newargs, **kwargs)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if (isinstance(result, decimal.Decimal)
and not isinstance(result, MyDecimal)):
return MyDecimal(str(result))
return result
if func.__name__ == '__new__':
return wrapper_for_new
return wrapper
class MyDecimal(decimal.Decimal, metaclass=AutoNormalizedDecimal):
def __str__(self):
return decimal.Decimal.__str__(self).replace('.', ',')
n = MyDecimal('-5423.5420000')
def speedtest():
import time
start = time.time()
d = decimal.Decimal('6')
for i in range(1000000):
d += decimal.Decimal(str(i))
print(time.time()-start)
start = time.time()
d = MyDecimal('6')
for i in range(1000000):
d += MyDecimal(str(i))
print(time.time()-start)
Here is how this works:
>>> n
Decimal('-5423.542')
>>> type(n)
<class '__main__.MyDecimal'>
>>> str(n)
'-5423,542'
>>> x = MyDecimal('542.63') / MyDecimal('5.2331')
>>> x
Decimal('103.6918843515315969501824922')
>>> type(x)
<class '__main__.MyDecimal'>
>>> y = MyDecimal('5.5252') - MyDecimal('0.0052')
>>> y
Decimal('5.52')
>>> z = decimal.Decimal('5.5252') - decimal.Decimal('0.0052')
>>> z
Decimal('5.5200')
Thanks in advance!
PS: Credit goes to Anurag Uniyal for his code which gave me a way to start: https://stackoverflow.com/a/3468410/2334951
EDIT1: I came out to redefine as_tuple() method which I could call all the time I need the trimmed Decimal version:
class MyDecimal(decimal.Decimal):
def as_tuple(self):
sign, digits_, exponent = super().as_tuple()
digits = list(digits_)
while exponent < 0 and digits[-1] == 0:
digits.pop()
exponent += 1
while len(digits) <= abs(exponent):
digits.insert(0, 0)
return decimal.DecimalTuple(sign, tuple(digits), exponent)
def __str__(self):
as_tuple = self.as_tuple()
left = ''.join([str(d) for d in as_tuple[1][:as_tuple[2]]])
right = ''.join([str(d) for d in as_tuple[1][as_tuple[2]:]])
return ','.join((left, right))
Related
I want to create a LimitedPrecisionFloat class that would allow me to store a float with n-digits (I don't want to round the number, just cut the remaining digits). This is how I would like it to behave:
a = LimitedPrecisionFloat(3.45678, ndigits=3)
print(a) # 3.456
a += 0.11199
print(a) # 3.567
a -= 0.567999
print(a) # 3 (or 3.0 or 3.000)
print(a + 1.9999) # 4.999
# same with other arithmetic operators, ie.
print(LimitedPrecisionFloat(1.11111 * 9.0, 3) # 9.999
...
What I currently have is:
def round_down(x:float, ndigits:int):
str_x = str(x)
int_part = str(int(x))
fraction_part = str_x[str_x.find('.') + 1:]
fraction_part = fraction_part[:ndigits]
return float(int_part + '.' + fraction_part)
class LimitedPrecisionFloat(float):
def __new__(cls, x, ndigits:int):
return super(LimitedPrecisionFloat, cls).__new__(cls, round_down(x, ndigits))
def __init__(self, x, ndigits: int):
super().__init__()
self.ndigits = ndigits
def __add__(self, other):
return round_down(float(self) + other, ndigits=self.ndigits)
def __sub__(self, other):
return round_down(float(self) - other, ndigits=self.ndigits)
# other operators
However, this will not work, because whenever __add__ (or any other operator) is called, it returns float and the precision is back in the number. So when I tried doing something like this:
def __add__(self, other):
return LimitedPrecisionFloat(float(self) + other, ndigits=self.ndigits)
But then I got the max recursion depth error.
Because of that, I also don't have a clue on how to implement augmented arithmetic assignments, like __iadd__.
I just made a generic number class.
this class is so simple, descriptions are below
from any ordered character list, make number class representing that ordered character list.
create_number_class("01") returns binary number class
create_number_class("0123456789") returns decimal number class
create_number_class("abcdefghij") return decimal number class but representing each digit as a alphabet.
belows is generic number class definition.
I think it is well-made class definition.
are there something needed improvement in that class definition?
thank you all. always.
ex)
ABC_Class = create_number_class("abc")
x = ABC_Class("baa")
y = ABC_Class("bbb")
print(x+y)
#output digits: abc, v: cbb, decimal_v: 22
below is class definition
def create_number_class(alphabet):
class temp(object):
digits = alphabet
def __init__(self, v):
self.v = v
self.decimal_v = self.to_decimal(self)
#staticmethod
def to_decimal(self):
r = 0
for i in range(0, len(self.v)):
r += len(temp.digits)**(len(self.v)-i-1)*(temp.digits.index(self.v[i]))
return r
#classmethod
def from_decimal(cls, decimal_v):
r = []
mod = len(temp.digits)
if decimal_v < mod:
return cls(temp.digits[decimal_v])
while True:
remainder = decimal_v % mod
r.append(remainder)
decimal_v = int((decimal_v - remainder)/ mod)
if decimal_v < mod:
r.append(decimal_v)
break
r = "".join(list(reversed([temp.digits[x] for x in r])))
#r = "".join(list(reversed([str(temp.digits.index(str(x))) for x in r])))
return cls(r)
def __add__(self, other):
return temp.from_decimal(self.decimal_v+other.decimal_v)
def __sub__(self, other):
return temp.from_decimal(self.decimal_v-other.decimal_v)
def __mul__(self, other):
return temp.from_decimal(self.decimal_v*other.decimal_v)
def __floordiv__(self, other):
return temp.from_decimal(self.decimal_v//other.decimal_v)
def __str__(self):
return "digits: {}, v: {}, decimal_v: {}".format(temp.digits, self.v, self.decimal_v)
def convert_to(self, new_class):
return new_class.from_decimal(self.decimal_v)
return temp
below are example
BinClass = create_number_class("01")
DecimalClass = create_number_class("0123456789")
x = BinClass("111")
x = BinClass("1000")
y = BinClass("10")
HexClass = create_number_class('0123456789ABCDEF')
x = HexClass('1')
y = HexClass('AA')
print(x+y)
print(x-y)
print(x*y)
print(x//y)
print(x.convert_to(DecimalClass))
isinstance(x, BinClass)
I would like to know how to define a new numerical base in Python.
For example:
base dimension = 4
Charset = 'u', '$', '6', '}' (from the least important to the most)
I would like to know how to create and handle it, to be able to do simple arithmetic like:
$} + 6u * 6 = $$}
7 + 8 * 2 = 23
I know I could use replace to replace u -> 0, $ -> 1 and so on, and use the int() function. However int() is not defined for base > 36, and I will have to handle these cases.
I know I could make my own function to convert them to base 10, do the math, and convert them back, but I would like to avoid that if possible.
Rather than replace, you can use dictionaries to translate back and forth between the charset and regular ints, something like:
charset = 'u$6}'
b = len(charset) #base
vals = {c:i for i,c in enumerate(charset)}
digits = {vals[c]: c for c in vals} #inverse dictionary
def toInt(s):
return sum(vals[c]*b**i for i,c in enumerate(reversed(s)))
def toNewBase(n):
nums = [] if n > 0 else [0]
while n > 0:
n,r = divmod(n,b)
nums.append(r)
return ''.join(digits[i] for i in reversed(nums))
def add(s,t):
return toNewBase(toInt(s) + toInt(t))
def subtract(s,t):
return toNewBase(toInt(s) - toInt(t))
def multiply(s,t):
return toNewBase(toInt(s) * toInt(t))
def divide(s,t):
return toNewBase(toInt(s) // toInt(t))
typical output:
>>> add('$}',multiply('6u','6'))
'$$}'
def str_base(number, base):
# http://stackoverflow.com/a/24763277/3821804
(d,m) = divmod(number,len(base))
if d > 0:
return str_base(d,base)+base[m]
return base[m]
def charset(chars):
class cls(int):
__slots__ = ()
def __new__(cls, src):
if isinstance(src, str):
return int.__new__(
cls,
''.join(str(chars.index(i)) for i in src),
len(chars)
)
return int.__new__(cls, src)
def __str__(self):
return str_base(self, chars)
def __repr__(self):
return '%s(%r)' % (type(self).__name__, str(self))
cls.__name__ = 'charset(%r)' % chars
return cls
Usage:
test = charset('u$6}')
print(test( test('$}') + test('6u') * test('6') ) ) # => '$$}'
See it working online: http://rextester.com/WYSE48066
At the moment, I'm too tired to explain it.
I was trying to port a function from C to Python and to make it easy to debug, I'd prefer it performed the same CPU word-size limited operations so I could compare the intermediate results. In other words, I'd like something like:
a = UnsignedBoundedInt(32, 399999)
b = UnsignedBoundedInt(32, 399999)
print(a*b) # prints 1085410049 (159999200001 % 2**32)
What's the best way to achieve this so that all operations (including bitwise shifts) would work as in C?
You can try using ctypes.uint_32 to bound the results for you:
>>> import ctypes
>>> print ctypes.c_uint32(399999 * 399999).value
1085410049
Alternatively you can use numpy's data types:
>>> import numpy as np
>>> a = np.uint32(399999)
>>> b = np.uint32(399999)
>>> a * b
__main__:1: RuntimeWarning: overflow encountered in uint_scalars
1085410049
Here's an interesting solution, though it only works under Python 2:
class U32:
"""Emulates 32-bit unsigned int known from C programming language."""
def __init__(self, num=0, base=None):
"""Creates the U32 object.
Args:
num: the integer/string to use as the initial state
base: the base of the integer use if the num given was a string
"""
if base is None:
self.int_ = int(num) % 2**32
else:
self.int_ = int(num, base) % 2**32
def __coerce__(self, ignored):
return None
def __str__(self):
return "<U32 instance at 0x%x, int=%d>" % (id(self), self.int_)
def __getattr__(self, attribute_name):
print("getattr called, attribute_name=%s" % attribute_name)
# you might want to take a look here:
# https://stackoverflow.com/q/19611001/1091116
r = getattr(self.int_, attribute_name)
if callable(r): # return a wrapper if integer's function was requested
def f(*args, **kwargs):
if args and isinstance(args[0], U32):
args = (args[0].int_, ) + args[1:]
ret = r(*args, **kwargs)
if ret is NotImplemented:
return ret
if attribute_name in ['__str__', '__repr__', '__index__']:
return ret
ret %= 2**32
return U32(ret)
return f
return r
print(U32(4) / 2)
print(4 / U32(2))
print(U32(4) / U32(2))
For Python 3 compatibility, have a look here.
I'm getting a getting a TypeError for unbound method (at the bottom). I'm teaching myself Python so this may be some simple mistake. The issue is with outFormat(), which didn't give me problems when I test it by itself but is not working within the class. Here's the class:
class gf2poly:
#binary arithemtic on polynomials
def __init__(self,expr):
self.expr = expr
def id(self):
return [self.expr[i]%2 for i in range(len(self.expr))]
def listToInt(self):
result = gf2poly.id(self)
return int(''.join(map(str,result)))
def prepBinary(a,b):
a = gf2poly.listToInt(a); b = gf2poly.listToInt(b)
bina = int(str(a),2); binb = int(str(b),2)
a = min(bina,binb); b = max(bina,binb);
return a,b
def outFormat(raw):
raw = str(raw); g = []
[g.append(i) for i,c in enumerate(raw) if c == '1']
processed = "x**"+' + x**'.join(map(str, g[::-1]))
#print "processed ",processed
return processed
def divide(a,b): #a,b are lists like (1,0,1,0,0,1,....)
a,b = gf2poly.prepBinary(a,b)
bitsa = "{0:b}".format(a); bitsb = "{0:b}".format(b)
difflen = len(str(bitsb)) - len(str(bitsa))
c = a<<difflen; q=0
while difflen >= 0 and b != 0:
q+=1<<difflen; b = b^c
lendif = abs(len(str(bin(b))) - len(str(bin(c))))
c = c>>lendif; difflen -= lendif
r = "{0:b}".format(b); q = "{0:b}".format(q)
#print "r,q ",type(r),type(q)
return r,q #returns r remainder and q quotient in gf2 division
def remainder(a,b): #separate function for clarity when calling
r = gf2poly.divide(a,b)[0]; r = int(str(r),2)
return "{0:b}".format(r)
def quotient(a,b): #separate function for clarity when calling
q = gf2poly.divide(a,b)[1]; q = int(str(q),2)
return "{0:b}".format(q)
This is how I'm calling it:
testp = gf2poly.quotient(f4,f2)
testr = gf2poly.remainder(f4,f2)
print "quotient: ",testp
print "remainder: ",testr
print "***********************************"
print "types ",type(testp),type(testr),testp,testr
testp = str(testp)
print "outFormat testp: ",gf2poly.outFormat(testp)
#print "outFormat testr: ",gf2poly.outFormat(testr)
This is the error:
TypeError: unbound method outFormat() must be called with gf2poly instance as first argument (got str instance instead)
Where you have this:
def outFormat(raw):
You probably want either this:
def outFormat(self, raw):
Or this:
#staticmethod
def outFormat(raw):
The former if you eventually need access to self in outFormat(), or the latter if you do not (as currently is the case in the posted code).