python中浮点数的表⽰⽅法_很好地在python中表⽰浮点数我想将浮点数表⽰为四舍五⼊到⼀定位数的字符串,并且从不使⽤指数格式。 本质上,我想显⽰任何浮点数并确保它看起来不错。
这个问题有⼏个部分:
我需要能够指定
有效位数。
有效位数
需要是可变的,不能是
⽤字符串格式化完成
操作员。 [编辑]我已经改正了; 字符串格式化操作符可以做到这⼀点。
我需要将其四舍五⼊
⼈会期望的,不是什么
像1.999999999999
我已经想出了⼀种⽅法来执⾏此操作,尽管它看起来像是⼀轮⼯作,⽽且还不是很完美。 (最⼤精度为15个有效数字。)
>>> def f(number, sigfig):
return ("%.15f" % (round(number, int(-1 * floor(log10(number)) + (sigfig - 1))))).rstrip("0").rstrip(".")
>>> print f(0.1, 1)
0.1
>>> print f(0.0000000000368568, 2)
0.000000000037
>>> print f(756867, 3)
757000
有⼀个更好的⽅法吗? 为什么Python对此没有内置函数?
是否有为此提供内置功能的语⾔?
以防万⼀:您知道%。* g%(3,3.142596)格式化选项吗? (尤其是星号)
我确实错过了星号格式选项,但是使⽤g返回指数并且使⽤f远⾮完美:"%。* f"%(0,34500000000000000000000)返回34499999999999999000000
您没有说这是您在做什么,但是如果您使⽤浮点数学来进⾏与⾦钱相关的计算,那将是⼀个可怕的想法。 使⽤⼩数模块或将数量存储为整数美分(或等值的本地货币)。 ⼩数确实是您最好的选择。
似乎没有内置的字符串格式化技巧,可以让您(1)打印浮点数的第⼀个有效数字出现在⼩数点后15位,以及(2)不使⽤科学计数法。这样就可以进⾏⼿动字符串操作了。
下⾯,我使⽤decimal模块从浮点数中提取⼗进制数字。
float_to_decimal函数⽤于将浮点数转换为decimal对象。 decimal.Decimal(str(f))的明显⽅法是错误的,因为str(f)可能会丢失有效数字。
float_to_decimal从⼗进制模块的⽂档中删除。
⼀旦将⼗进制数字作为整数元组获得,下⾯的代码就可以完成以下⼯作:截取所需数量的有效数字,如果需要,将其四舍五⼊,将数字连成⼀个字符串,在符号上加⼤头,然后放置⼀个⼩数点和零在左边或右边(视情况⽽定)。
在底部,您会发现⼀些我⽤来测试f函数的情况。
import decimal
def float_to_decimal(f):
"Convert a floating point number to a Decimal with no loss of information" n, d = f.as_integer_ratio()
numerator, denominator = decimal.Decimal(n), decimal.Decimal(d)
ctx = decimal.Context(prec=60)
result = ctx.divide(numerator, denominator)
while ctx.flags[decimal.Inexact]:
ctx.flags[decimal.Inexact] = False
ctx.prec *= 2
result = ctx.divide(numerator, denominator)
return result
def f(number, sigfig):
assert(sigfig>0)
try:
d=decimal.Decimal(number)
except TypeError:
d=float_to_decimal(float(number))
sign,digits,exponent=d.as_tuple()
if len(digits) < sigfig:
digits = list(digits)
shift=d.adjusted()
result=int(''.join(map(str,digits[:sigfig])))
# Round the result
if len(digits)>sigfig and digits[sigfig]>=5: result+=1
result=list(str(result))
# Rounding can change the length of result
# If so, adjust shift
shift+=len(result)-sigfig
# reset len of result to sigfig
result=result[:sigfig]
if shift >= sigfig-1:
# Tack more zeros on the end
result+=['0']*(shift-sigfig+1)
elif 0<=shift:
# Place the decimal point in between digits
result.insert(shift+1,'.')
else:
# Tack zeros on the front
assert(shift<0)
python货币转换result=['0.']+['0']*(-shift-1)+result
if sign:
result.insert(0,'-')
return ''.join(result)
if __name__=='__main__':
tests=[
(0.1, 1, '0.1'),
(0.0000000000368568, 2,'0.000000000037'),
(0.00000000000000000000368568, 2,'0.0000000000000000000037'), (756867, 3, '757000'),
(-756867, 3, '-757000'),
(-756867, 1, '-800000'),
(0.0999999999999,1,'0.1'),
(0.00999999999999,1,'0.01'),
(0.00999999999999,2,'0.010'),
(0.0099,2,'0.0099'),
(1.999999999999,1,'2'),
(1.999999999999,2,'2.0'),
(34500000000000000000000, 17, '34500000000000000000000'),
('34500000000000000000000', 17, '34500000000000000000000'), (756867, 7, '756867.0'),
]
for number,sigfig,answer in tests:
try:
result=f(number,sigfig)
assert(result==answer)
print(result)
except AssertionError:
print('Error',number,sigfig,result,answer)
那就是⼀些漂亮的代码。这正是我想要的。如果将其更改为采⽤⼩数⽽不是浮点数(这样做很简单),那么我们可以⼀起避免浮点错误。我发现的唯⼀问题是长整数。例如,尝试(34500000000000000000000, 17, 34500000000000000000000)。但是,这再次可能只是浮点错误引起的。
接得好。我对d的定义做了些微更改,该定义解决了使⽤长整数的问题,并且作为副作⽤,它还允许您也为number arg传递数字字符串。
该修复程序有效,但是我发现了其他不相关的错误。使⽤(756867, 7, 756867.0),我得到了75686.7。似乎填充结果的条件有些差。
是的,那就是另⼀个好收获。我已经编辑了我的代码。
嗯,我想我喜欢您如何更好地处理它。再次编辑我的帖⼦...
如果要浮点精度,则需要使⽤decimal模块,该模块是Python标准库的⼀部分:
>>> import decimal
>>> d = decimal.Decimal('0.0000000000368568')
>>> print '%.15f' % d
0.000000000036857
⼗进制模块看起来可能会有所帮助,但这确实不能回答我的问题。
@ dln385:怎么样?它满⾜您列出的所有要求。
1.指定精度,⽽不是有效数字。有很⼤的不同。
2.它不会舍⼊到⼩数点后。例如,带有3个有效数字的756867是757000。请参阅原始问题。
3.该⽅法会分解为⼤数,例如长整数。
@ dln385:您阅读过⽂档吗? 1."⼗进制模块包含有效位的概念,因此1.30 + 1.20为2.50。保留尾随零以表⽰有效。这是货币应⽤的惯⽤表⽰法。对于乘法,"教科书"⽅法使⽤所有数字例如,1.3 * 1.2等于1.56,⽽1.30 * 1.20等于1.5600。" 2.它使⽤固定点⽽不是浮点数,因此您⼀开始就不会遇到此类问
题,并且3.⼩数模块⽀持任意精度。
@Billy ONeal:是的,我确实阅读了⽂档。在我的最后⼀条评论中,我正在解释为什么%.15f % d没有回答我的问题。⾄于⼀般的⼗进制模块,我不到四舍五⼊到有效数字(包括⼩数点左边)或显⽰不带指数的数字的⽅法。另外,应注意,即使使⽤⼩数,%.15f % d仍会分解为⼤整数。
以下是根据给定的误差线格式化值的代码段。
from math import floor, log10, round
def sigfig3(v, errplus, errmin):
i = int(floor(-log10(max(errplus,errmin)) + 2))
if i > 0:
fmt ="%%.%df" % (i)
return"{%s}^{%s}_{%s}" % (fmt % v,fmt % errplus, fmt % errmin)
else:
return"{%d}^{%d}_{%d}" % (round(v, i),round(errplus, i), und(i))
例⼦:
5268685 (+1463262,-2401422) becomes 5300000 (+1500000,-2400000)
0.84312 +- 0.173124 becomes 0.84 +- 0.17
需要任意精度的浮点数才能正确回答此问题。因此,必须使⽤⼗进制模块。没有办法不使⽤指数格式就将⼩数转换为字符串(原始问题的⼀部分),所以我写了⼀个函数来做到这⼀点:
def removeExponent(decimal):
digits = [str(n) for n in decimal.as_tuple().digits]
length = len(digits)
exponent = decimal.as_tuple().exponent
if length <= -1 * exponent:
zeros = -1 * exponent - length
digits[0:0] = ["0."] + ["0"] * zeros
elif 0 < -1 * exponent < length:
digits.insert(exponent,".")
elif 0 <= exponent:
sign = []
if decimal.as_tuple().sign == 1:
sign = ["-"]
print"".join(sign + digits)
问题正在设法取整重要数字。⼩数的" quantize()"⽅法不会舍⼊到⼩数点以上,并且" round()"函数始终返回浮点数。我不知道这些是否是bug,但这意味着舍⼊⽆限精度浮点数的唯⼀⽅法是将其解析为列表或字符串并⼿动进⾏舍⼊。换句话说,这个问题没有理智的答案。
您不需要任意精度的浮点数。请注意,他从未将舍⼊的答案视为浮点数,⽽只是将其视为字符串。 BTW -1 * anything可以写为-anything。
我不明⽩您的"不会舍⼊⾼于⼩数点"。尝试:例如,Decimal(123.456).quantize(Decimal(1e1))。
顺便说⼀句,四舍五⼊⼀个Decimal实例会在Python 3.x中返回另⼀个Decimal。
@Mark Dickinson:是的,我没想到Decimal(123.456).quantize(Decimal(10))会有不同的⾏为。另外,如果Decimal四舍五⼊在Python 3.x中返回Decimal,那么似乎是该升级的时候了。感谢您的指导。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论