十进制类型的替代 [英] Alternative to Decimal type

查看:68
本文介绍了十进制类型的替代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好


我对''十进制''类型有标准要求,要实例化和

操纵存储在a中的数字数据数据库。在推出Decimal类型之前我想出了一个

的解决方案,其中

对我来说效果很好。我事先知道这个数字的''scale''(小数位数)。当我从

数据库中读取数字时,我将其扩展为整数。当我把它写回来时,我再次缩小它b / b
。所有算术都是使用整数完成的,所以我不会丢失

的准确度。


这种方法有一个不便之处。例如,如果我的产品数量为4美元,产品数量为4,价格为2,

我希望将它们相乘得到一个值2的比例,我有
要记住将结果缩小4.这是一个小工作,并且

错误很快通过测试得到,但它确实使代码变得有点麻烦,所以找到解决方案会很好。


我现在正在做一些重构,并决定采取一个看看

十进制类型。我最初的印象是,使用它是非常尴尬的,我不需要它的高级功能,而且它没有

帮助解决我提到的一个问题以上。


因此我花了一些时间尝试一种符合我特殊要求的数字类型

。我想出了一些

似乎有用的东西,我在下面展示。


我有两个问题。


1.我做了什么明显的问题?


2.我是否不必要地重新发明轮子?即我可以使用Decimal类型轻松地完成

等效吗?


----------------- ---
来自__future__进口部门的


类号(对象):

def __init __(自我,价值,规模) :

self.factor = 10.0 ** scale

if isinstance(value,Number):

value = value.value / value.factor

self.value = long(round(value * self.factor))

self.scale = scale


def __add__ (自我,其他):

if isinstance(其他,编号):

其他= other.value / other.factor

返回编号( (self.value / self.factor)+ other,self.scale)


def __sub __(self,other):

if isinstance(other,Number) ):

other = other.value / other.factor

返回数字((self.value / self.factor)-other,self.scale)


def __mul __(self,other):

if isinstance(other,Number):

other = other.value / other.factor

返回Number( (self.value / self.factor)*其他,self.scale)


def __truediv __(自我,其他):

if isinstance(其他,编号) ):

other = other.value / other.factor

返回Number((self.value / self.factor)/other,self.scale)


def __radd __(自我,其他):

返回self .__添加__(其他)


def __rsub __(self,other) :

返回数字(其他 - (self.value / self.factor),self.scale)


def __rmul __(自我,其他):

返回self .__ mul __(其他)


def __rtruediv __(自我,其他):

返回Number(其他/(self.value) /self.factor),self.scale)


def __cmp __(自我,其他):

if isinstance(other,Number):

other = other.value / other.factor

this = self.value / self.factor

if this<其他:

返回-1

elif这个:

返回1

否则:

返回0


def __str __(自我):

s = str(self.value)

如果s [0 ] =='' - '':

减去='' - ''

s = s [1:]。zfill(self.scale + 1)

else:

减去=''''

s = s.zfill(self.scale + 1)

return' '%s%s。%s''%(减去,s [: - self.scale],s [-self.scale:])

---------- ----------


示例用法 -


>>> qty =数字(12.5,4)
价格=数字(123.45,2)

< blockquote class =post_quotes>


>>>打印价格*数量



1543.13 [比例来自左手操作数]


>>> print qty * price



1543.1250 [比例取自左侧操作数]


>>>打印数字(数量*价格,2)



1543.13 [规模是取自数字实例]

--------------------


在这个阶段,我有没有内置任何舍入选项,但如果我发现需要它,可以稍后再做。


欢迎任何评论。


谢谢


Frank Millman

解决方案

6月9日,5日:11 * pm,Frank Millman< fr ... @ chagford.comwrote:


我对''deci有一个标准要求mal''type,to instantiate和

操纵存储在数据库中的数字数据。在推出Decimal类型之前我想出了一个

的解决方案,其中

对我来说效果很好。我事先知道这个数字的''scale''(小数位数)。当我从

数据库中读取数字时,我将其扩展为整数。当我把它写回来时,我再次缩小它b / b
。所有算术都是使用整数完成的,所以我不会丢失

的准确度。


这种方法有一个不便之处。例如,如果我的产品数量为4美元,产品数量为4,价格为2,

我希望将它们相乘得到一个值2的比例,我有
要记住将结果缩小4.这是一个小工作,并且

错误很快通过测试得到,但它确实使代码变得有点麻烦,所以找到解决方案会很好。


我现在正在做一些重构,并决定采取一个看看

十进制类型。我最初的印象是,使用它是非常尴尬的,我不需要它的高级功能,而且它没有

帮助解决我提到的一个问题以上。


因此我花了一些时间尝试一种符合我特殊要求的数字类型

。我想出了一些

似乎有用的东西,我在下面展示。


我有两个问题。


1.我做了什么明显的问题?


2.我是否不必要地重新发明轮子?即我可以使用Decimal类型轻松地完成

等价物吗?



嗨弗兰克,

我不知道为什么你认为十进制是复杂的:它有一些

高级功能,但是对于你似乎正在做的事情应该很容易用它替换你的''数字'。事实上,它使事情更简单,因为你不必担心''规模''。


您的示例很容易转换:


来自十进制导入十进制

数量=十进制(''12.5'​​')

price =十进制('''123.45'')


打印价格*数量

打印数量*价格

打印(数量*价格).quantize(十进制(''0.01) ''))


-

Paul Hankin


6月9日,10:54 * am,Paul Hankin< paul.han ... @ gmail.comwrote:


>

嗨Frank,
我不知道为什么你认为十进制是复杂的:它有一些

高级功能,但对于你似乎正在做的事情应该很容易

用它替换你的''数字''。事实上,它使事情更简单,因为你不必担心''规模''。


您的示例很容易转换:


来自十进制导入十进制

数量=十进制(''12.5'​​')

price =十进制('''123.45'')


打印价格*数量

打印数量*价格

打印(数量*价格).quantize(十进制(''0.01) ''))



我以为我可能会遗漏一些明显的东西。这确实看起来很简单。谢谢,保罗


Frank


6月9日下午4:06 *,Frank Millman< fr ... @ chagford.comwrote:


>

感谢您的回复,Mel。我不太明白你的意思。



经常发生这种情况,在我发送回复之后,我重新阅读了你的帖子,我想知道你知道你得到的是什么。


我的方法的一个问题是,每次创建新实例时,我都会将结果缩减为所需的比例因子。如果我在计算中将一系列实例链接在一起,那么

可能会导致精度损失。我认为你的建议避免了这个问题。


我会再次仔细阅读你的信息。我想这将导致我的方法重新考虑




再次感谢


Frank


PS尽管我早些时候回复保罗,但我没有放弃使用我的Number类而不是标准Decimal类的想法




我做了一个简单的测试创建两个实例并使用两种方法将它们加在一起

,并对它们进行计时。十进制出来比数字慢了几美元。


重要吗?不知道,但可能是。


Hi all

I have a standard requirement for a ''decimal'' type, to instantiate and
manipulate numeric data that is stored in a database. I came up with a
solution long before the introduction of the Decimal type, which has
been working well for me. I know the ''scale'' (number of decimal
places) of the number in advance. When I read the number in from the
database I scale it up to an integer. When I write it back I scale it
down again. All arithmetic is done using integers, so I do not lose
accuracy.

There is one inconvenience with this approach. For example, if I have
a product quantity with a scale of 4, and a price with a scale of 2,
and I want to multiply them to get a value with a scale of 2, I have
to remember to scale the result down by 4. This is a minor chore, and
errors are quickly picked up by testing, but it does make the code a
bit messy, so it would be nice to find a solution.

I am now doing some refactoring, and decided to take a look at the
Decimal type. My initial impressions are that it is quite awkward to
use, that I do not need its advanced features, and that it does not
help solve the one problem I have mentioned above.

I therefore spent a bit of time experimenting with a Number type that
suits my particular requirements. I have come up with something that
seems to work, which I show below.

I have two questions.

1. Are there any obvious problems in what I have done?

2. Am I reinventing the wheel unnecessarily? i.e. can I do the
equivalent quite easily using the Decimal type?

--------------------
from __future__ import division

class Number(object):
def __init__(self,value,scale):
self.factor = 10.0**scale
if isinstance(value,Number):
value = value.value / value.factor
self.value = long(round(value * self.factor))
self.scale = scale

def __add__(self,other):
if isinstance(other,Number):
other = other.value / other.factor
return Number((self.value/self.factor)+other,self.scale)

def __sub__(self,other):
if isinstance(other,Number):
other = other.value / other.factor
return Number((self.value/self.factor)-other,self.scale)

def __mul__(self,other):
if isinstance(other,Number):
other = other.value / other.factor
return Number((self.value/self.factor)*other,self.scale)

def __truediv__(self,other):
if isinstance(other,Number):
other = other.value / other.factor
return Number((self.value/self.factor)/other,self.scale)

def __radd__(self,other):
return self.__add__(other)

def __rsub__(self,other):
return Number(other-(self.value/self.factor),self.scale)

def __rmul__(self,other):
return self.__mul__(other)

def __rtruediv__(self,other):
return Number(other/(self.value/self.factor),self.scale)

def __cmp__(self,other):
if isinstance(other,Number):
other = other.value / other.factor
this = self.value / self.factor
if this < other:
return -1
elif this other:
return 1
else:
return 0

def __str__(self):
s = str(self.value)
if s[0] == ''-'':
minus = ''-''
s = s[1:].zfill(self.scale+1)
else:
minus = ''''
s = s.zfill(self.scale+1)
return ''%s%s.%s'' % (minus, s[:-self.scale], s[-self.scale:])
--------------------

Example usage -

>>>qty = Number(12.5,4)
price = Number(123.45,2)

>>>print price * qty

1543.13 [scale is taken from left-hand operand]

>>>print qty * price

1543.1250 [scale is taken from left-hand operand]

>>>print Number(qty * price,2)

1543.13 [scale is taken from Number instance]
--------------------

At this stage I have not built in any rounding options, but this can
be done later if I find that I need it.

Any comments will be welcome.

Thanks

Frank Millman

解决方案

On Jun 9, 5:11*pm, Frank Millman <fr...@chagford.comwrote:

I have a standard requirement for a ''decimal'' type, to instantiate and
manipulate numeric data that is stored in a database. I came up with a
solution long before the introduction of the Decimal type, which has
been working well for me. I know the ''scale'' (number of decimal
places) of the number in advance. When I read the number in from the
database I scale it up to an integer. When I write it back I scale it
down again. All arithmetic is done using integers, so I do not lose
accuracy.

There is one inconvenience with this approach. For example, if I have
a product quantity with a scale of 4, and a price with a scale of 2,
and I want to multiply them to get a value with a scale of 2, I have
to remember to scale the result down by 4. This is a minor chore, and
errors are quickly picked up by testing, but it does make the code a
bit messy, so it would be nice to find a solution.

I am now doing some refactoring, and decided to take a look at the
Decimal type. My initial impressions are that it is quite awkward to
use, that I do not need its advanced features, and that it does not
help solve the one problem I have mentioned above.

I therefore spent a bit of time experimenting with a Number type that
suits my particular requirements. I have come up with something that
seems to work, which I show below.

I have two questions.

1. Are there any obvious problems in what I have done?

2. Am I reinventing the wheel unnecessarily? i.e. can I do the
equivalent quite easily using the Decimal type?

Hi Frank,
I don''t know why you think Decimal is complicated: it has some
advanced features, but for what you seem to be doing it should be easy
to replace your ''Number'' with it. In fact, it makes things simpler
since you don''t have to worry about ''scale''.

Your examples convert easily:

from decimal import Decimal
qty = Decimal(''12.5'')
price = Decimal(''123.45'')

print price * qty
print qty * price
print (qty * price).quantize(Decimal(''0.01''))

--
Paul Hankin


On Jun 9, 10:54*am, Paul Hankin <paul.han...@gmail.comwrote:

>
Hi Frank,
I don''t know why you think Decimal is complicated: it has some
advanced features, but for what you seem to be doing it should be easy
to replace your ''Number'' with it. In fact, it makes things simpler
since you don''t have to worry about ''scale''.

Your examples convert easily:

from decimal import Decimal
qty = Decimal(''12.5'')
price = Decimal(''123.45'')

print price * qty
print qty * price
print (qty * price).quantize(Decimal(''0.01''))

I thought I might be missing something obvious. This does indeed look
easy. Thanks, Paul

Frank


On Jun 9, 4:06*pm, Frank Millman <fr...@chagford.comwrote:

>
Thanks for the reply, Mel. I don''t quite understand what you mean.

As so often happens, after I sent my reply I re-read your post and I
think I understand what you are getting at.

One problem with my approach is that I am truncating the result down
to the desired scale factor every time I create a new instance. This
could result in a loss of precision if I chain a series of instances
together in a calculation. I think that what you are suggesting avoids
this problem.

I will read your message again carefully. I think it will lead to a
rethink of my approach.

Thanks again

Frank

P.S. Despite my earlier reply to Paul, I have not abandoned the idea
of using my Number class as opposed to the standard Decimal class.

I did a simple test of creating two instances and adding them
together, using both methods, and timing them. Decimal came out 6
times slower than Number.

Is that important? Don''t know, but it might be.


这篇关于十进制类型的替代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆