Path: csiph.com!usenet.pasdenom.info!aioe.org!news.stack.nl!newsfeed.xs4all.nl!newsfeed2.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.004 X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'subject:not': 0.03; 'context': 0.07; 'float': 0.07; 'matches': 0.07; 'result,': 0.07; 'bug.': 0.09; 'trailing': 0.09; '0),': 0.16; 'ah,': 0.16; 'digits.': 0.16; 'precision,': 0.16; 'removed,': 0.16; 'subject:format': 0.16; 'zeroes': 0.16; 'zeros': 0.16; 'wrote:': 0.18; 'normally': 0.19; "skip:' 30": 0.19; 'thu,': 0.19; 'feb': 0.22; '>>>': 0.22; 'example': 0.22; 'import': 0.22; 'format,': 0.24; 'removed.': 0.24; 'specify': 0.24; 'string,': 0.24; 'looks': 0.24; '15,': 0.26; 'values': 0.27; 'header:In-Reply-To:1': 0.27; "doesn't": 0.30; 'message-id:@mail.gmail.com': 0.30; "skip:' 10": 0.31; 'decimal': 0.31; 'doc': 0.31; 'equivalent.': 0.31; 'languages': 0.32; 'supposed': 0.32; 'says': 0.33; 'there,': 0.34; 'skip:d 20': 0.34; "i'd": 0.34; 'knows': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'there': 0.35; 'version': 0.36; 'really': 0.36; 'yield': 0.36; 'should': 0.36; 'example,': 0.37; 'two': 0.37; 'version,': 0.38; 'to:addr:python-list': 0.38; 'pm,': 0.38; '12,': 0.39; 'subject:" ': 0.39; 'sure': 0.39; 'to:addr:python.org': 0.39; 'how': 0.40; 'numbers': 0.61; "you're": 0.61; 'first': 0.61; "you've": 0.63; 'such': 0.63; 'telling': 0.64; 'default': 0.69; 'behavior': 0.77; '2015': 0.84; 'notion': 0.91 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type:content-transfer-encoding; bh=XPMssaGutQpVpKGtbCX0VuAD0UXyfEwR/t/hVRGD89U=; b=Lo5bxCIOhyIS8J+HWuRKFPz2YXmVWdOlh0L5qgC47v4UcvLJoE/Sf7p9+vpmejnUdq 2tThsbnIZjFWD/yyq4qzTvp+5sGVgVFREcYe+Bl5pdqIByt9CgOoKOnpiz24xwlKOE9V afQQWJvAaxYW3Uc6GVbk/IX/0ntzrfccZV3bJI3f0oEZcz4iHuIsvk91tZU3SKl3+D2A 0MiFu/gABYAPr+buektqLF3wzxju9a4P0yeOo188gryEtNskTdfRgaiSutJh29p9dJ5Y YGU4yV6VohQn35znSdBLr65aDjy6A2JHi8uYgwai40qy+5a4cJcoMxxmphVBgItJkwaS pPOA== X-Received: by 10.70.135.165 with SMTP id pt5mr10093747pdb.101.1423784808026; Thu, 12 Feb 2015 15:46:48 -0800 (PST) MIME-Version: 1.0 In-Reply-To: References: From: Ian Kelly Date: Thu, 12 Feb 2015 16:46:07 -0700 Subject: Re: Floating point "g" format not stripping trailing zeros To: Python Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 65 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1423784816 news.xs4all.nl 2871 [2001:888:2000:d::a6]:36792 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:85617 On Thu, Feb 12, 2015 at 1:23 PM, Hrvoje Nik=C5=A1i=C4=87 wrote: >> >>>>> from decimal import Decimal as D >> >>>>> x =3D D(1)/D(999) >> >>>>> '{:.15g}'.format(x) >> >> >> >> '0.00100100100100100' > [...] >> > I'd say it's a bug. P is 15, you've got 17 digits after the decimal p= lace >> > and two of those are insignificant trailing zeros. >> >> Actually it's the float version that doesn't match the documentation. >> In the decimal version, sure there are 17 digits after the decimal >> place there, but the first two -- which are leading zeroes -- would >> not normally be considered significant. > > {:.15g} is supposed to give 15 digits of precision, but with trailing > zeros removed. The doc says with "insignificant" trailing zeros removed, not all trailing zeros. > For example, '{:.15g}'.format(Decimal('0.5')) should > yield '0.5', not '0.500000000000000' -- and, it indeed does. It is > only for some numbers that trailing zeros are not removed, which looks > like a bug. The behavior of floats matches both the documentation and > other languages using the 'g' decimal format, such as C. Ah, I see now what's going on here. With floats, there is really no notion of significant digits. The values 0.5 and 0.50000 are completely equivalent. With decimals, that's not exactly true; if you give the decimal a trailing zero then you are telling it that the zero is significant. >>> Decimal('0.5') Decimal('0.5') >>> Decimal('0.50000') Decimal('0.50000') >>> Decimal('0.5').as_tuple() DecimalTuple(sign=3D0, digits=3D(5,), exponent=3D-1) >>> Decimal('0.50000').as_tuple() DecimalTuple(sign=3D0, digits=3D(5, 0, 0, 0, 0), exponent=3D-5) These are distinct; the decimal knows how many significant digits you passed it. As a result, these are also distinct: >>> '{:.4g}'.format(Decimal('0.5')) '0.5' >>> '{:.4g}'.format(Decimal('0.50000')) '0.5000' Now what happens in your original example of 1/999? The default decimal context uses 28 digits of precision, so the result of that calculation will have 28 significant digits in it. >>> decimal.getcontext().prec 28 >>> Decimal(1) / Decimal(999) Decimal('0.001001001001001001001001001001') When you specify the a precision of 15 in your format string, you're telling it to take the first 15 of those. It doesn't care that the last couple of those are zeros, because as far as it's concerned, those digits are significant.