python语言中浮点数,在python中很好地表示一个浮点数

I want to represent a floating-point number as a string rounded to some number of significant digits, and never using the exponential format. Essentially, I want to display any floating-point number and make sure it “looks nice”.

There are several parts to this problem:

I need to be able to specify the

number of significant digits.

The number of significant digits

needs to be variable, which can't be

done with with the string formatting

operator. [edit] I've been corrected; the string formatting operator can do this.

I need it to be rounded the way a

person would expect, not something

like 1.999999999999

I've figured out one way of doing this, though it looks like a work-round and it's not quite perfect. (The maximum precision is 15 significant digits.)

>>> 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

Is there a better way to do this? Why doesn't Python have a built-in function for this?

解决方案

It appears there is no built-in string formatting trick which allows you to (1) print floats whose first significant digit appears after the 15th decimal place and (2) not in scientific notation. So that leaves manual string manipulation.

Below I use the decimal module to extract the decimal digits from the float.

The float_to_decimal function is used to convert the float to a Decimal object. The obvious way decimal.Decimal(str(f)) is wrong because str(f) can lose significant digits.

float_to_decimal was lifted from the decimal module's documentation.

Once the decimal digits are obtained as a tuple of ints, the code below does the obvious thing: chop off the desired number of sigificant digits, round up if necessary, join the digits together into a string, tack on a sign, place a decimal point and zeros to the left or right as appropriate.

At the bottom you'll find a few cases I used to test the f function.

import decimal

def float_to_decimal(f):

# http://docs.python.org/library/decimal.html#decimal-faq

"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):

# http://stackoverflow.com/questions/2663612/nicely-representing-a-floating-point-number-in-python/2663623#2663623

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)

digits.extend([0] * (sigfig - len(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)

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值