# How to detect a double's significant digits

15 views

### mrstephengross

May 5, 2005, 1:37:00 PM5/5/05
to
Hi all... How can I find out the number of significant digits (to the
right of the decimal place, that is) in a double? At least, I *think*
that's what I'm asking for. For instance:

0.103 --> 3
0.0103 --> 4
0.00103 --> 5
0.000103 --> 6
0.0000103 --> 7

--Steve (mrsteph...@hotmail.com)

### James Stroud

May 5, 2005, 1:51:29 PM5/5/05
to pytho...@python.org
Significant digits are an accounting concept. As such, it is up to the
accountant to keep track of these as only she knows the precision of her
measurements.

Koan for the day:

What are the significant digits of 0.1?

Hint:

>>> 0.1

James

On Thursday 05 May 2005 10:37 am, so sayeth mrstephengross:

--
James Stroud, Ph.D.
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

### mrstephengross

May 5, 2005, 1:57:43 PM5/5/05
to
So how can I get the kind of information I want then?

For example:

0.103 --> 3
0.0103 --> 4
0.00103 --> 5
0.000103 --> 6
0.0000103 --> 7

Any ideas?
--Steve

### phil

May 5, 2005, 2:04:21 PM5/5/05
to mrstephengross, pytho...@python.org
fl = 1.0002
x = str(fl)
pos = x.find('.')
print len( x[pos+1:] )
>>> 4

### mrstephengross

May 5, 2005, 2:13:46 PM5/5/05
to
Ok, that won't work. First of all, str() is not a function. If I want
to convert the float into a string, the conversion function will have
to use some kind of numeric precision, which will screw things up.
Consider this:

float f = 1.004;
ostringstream s;
s << f;
cout << s.str();

The above code may produce "1.004", or "1.0040", or "1.00400",
depending on the stream's precision setting. I need a way to detect the
number of digits to the right of decimal point *prior* to doing any
kind of string conversion.

--Steve

### Steven Bethard

May 5, 2005, 2:15:07 PM5/5/05
to
mrstephengross wrote:
> So how can I get the kind of information I want then?
>
> For example:
>
> 0.103 --> 3
> 0.0103 --> 4
> 0.00103 --> 5
> 0.000103 --> 6
> 0.0000103 --> 7

Beware that this is probably only relevant if you have your numbers as
strings, not as floats:

py> 0.103
0.10299999999999999

But, assuming you have your numbers as strings, I would suggest looking
at str.split() and len(). I'd give you an example, but this sounds
kinda like a homework assignment.

STeVe

### Steven Bethard

May 5, 2005, 2:17:15 PM5/5/05
to
mrstephengross wrote:
> First of all, str() is not a function.

Yes it is.

> float f = 1.004;
> ostringstream s;
> s << f;
> cout << s.str();

This doesn't look like Python to me. Are you sure you're on the right
newsgroup?

STeVe

### mrstephengross

May 5, 2005, 2:20:22 PM5/5/05
to
>But, assuming you have your numbers as strings, I would suggest
looking
at str.split() and len().

Well, the numbers are in fact stored as numbers, so string processing
won't work.

>I'd give you an example, but this sounds kinda like a homework
assignment.

The task may sound like it comes from class, but I can assure you that
I am indeed a professional developer. I'm doing some rather intricate
text processing / rendering stuff these days, and C++ is unfortunately
none too handy for that sort of thing. Unfortunately, I have to use it

Thanks,
--Steve

### Steven Bethard

May 5, 2005, 2:24:23 PM5/5/05
to
mrstephengross wrote:
> Well, the numbers are in fact stored as numbers, so string processing
> won't work.

What kind of numbers? Python floats?

STeVe

### Steven Bethard

May 5, 2005, 2:30:53 PM5/5/05
to
mrstephengross wrote:
>>But, assuming you have your numbers as strings, I would suggest
>
> looking
> at str.split() and len().
>
> Well, the numbers are in fact stored as numbers, so string processing
> won't work.

py> def digits(f):
... return len(str(f).split('.')[1].rstrip('0'))
...
py> for f in [0.103, 0.1030, 0.0103, 0.010300]:
... print f, digits(f)
...
0.103 3
0.103 3
0.0103 4
0.0103 4

I believe the rstrip is unnecessary because I think str() will never
produce additional following zeros, but you can guarantee it by calling
rstrip if you want.

Note that, for example, 0.103 and 0.1030 are identical as far as Python
is concerned, so I hope you're not hoping to show a difference between
these two...

STeVe

### Charles Krug

May 5, 2005, 2:42:17 PM5/5/05
to

I would say that each of these examples has three signficant figures.
Each of them can be expressed as:

1.03e+n

For any integer n.

The fact that you've only shown the cases where n \in {-1, -2, -3, -4,
-5 . . } doesn't change the generality of the answer.

### Grant Edwards

May 5, 2005, 2:43:51 PM5/5/05
to
On 2005-05-05, mrstephengross <mrsteph...@hotmail.com> wrote:
>>But, assuming you have your numbers as strings, I would suggest
> looking
> at str.split() and len().
>
> Well, the numbers are in fact stored as numbers,

Then your question is in fact meaningless. The related
question that can be answered is "where is the least
significant '1' bit in the IEEE representation". If that's

> so string processing won't work.

>>I'd give you an example, but this sounds kinda like a homework
>> assignment.
>
> The task may sound like it comes from class, but I can assure
> you that I am indeed a professional developer. I'm doing some
> rather intricate text processing / rendering stuff these days,
> and C++ is unfortunately none too handy for that sort of
> thing. Unfortunately, I have to use it for the task.

--
Grant Edwards grante Yow! Hmmm... A hash-singer
at and a cross-eyed guy were
visi.com SLEEPING on a deserted
island, when...

### mrstephengross

May 5, 2005, 3:14:41 PM5/5/05
to
>This doesn't look like Python to me. Are you sure you're on the right
newsgroup?

Er, ok, I'm an idiot. This was all supposed to be on comp.lang.c++, but
obviously I posted on the wrong one. Sorry for all the hassle. In
python, this stuff is a heck of a lot easier.

--Steve

### phil

May 5, 2005, 3:16:34 PM5/5/05
to mrstephengross, pytho...@python.org
Bollocks, works here.

That looks like Java!!! Aaaihh!

### Peter Otten

May 5, 2005, 3:29:36 PM5/5/05
to
mrstephengross wrote:

> This was all supposed to be on comp.lang.c++, but

http://mail.python.org/pipermail/python-dev/2004-March/043703.html

http://www.netlib.org/fp/

"""
file g_fmt.c
by David Gay
for ANSI C or C++ source for function g_fmt(char *, double):
, with help from dtoa, g_fmt(buf, x) sets buf to the shortest
, decimal string that correctly rounds to x and returns buf.
"""

Peter

### Fredrik Lundh

May 5, 2005, 3:30:13 PM5/5/05
to pytho...@python.org
"mrstephengross" wrote:

> >But, assuming you have your numbers as strings, I would suggest
> looking
> at str.split() and len().
>
> Well, the numbers are in fact stored as numbers, so string processing
> won't work.

if they're not strings, your question is meaningless. as others have
pointed out, the exact internal representation for 0.103 is more like
0.10299999999999999433786257441170164383947849273681640625
which has a lot more than 3 digits...

> >I'd give you an example, but this sounds kinda like a homework
> assignment.
>
> The task may sound like it comes from class, but I can assure you that
> I am indeed a professional developer.

well professional or not, you clearly need to refresh your floating point
skills. I suggest reading the following documents before proceeding:

</F>

### Jeremy Bowers

May 5, 2005, 4:32:38 PM5/5/05
to
On Thu, 05 May 2005 18:42:17 +0000, Charles Krug wrote:

> On 5 May 2005 10:37:00 -0700, mrstephengross <mrsteph...@hotmail.com>
> wrote:
>> Hi all... How can I find out the number of significant digits (to the
>> right of the decimal place, that is) in a double? At least, I *think*
>> that's what I'm asking for. For instance:
>>
>> 0.103 --> 3
>> 0.0103 --> 4
>> 0.00103 --> 5
>> 0.000103 --> 6
>> 0.0000103 --> 7
>>
>> --Steve (mrsteph...@hotmail.com)
>>
>>
> I would say that each of these examples has three signficant figures. Each
> of them can be expressed as:
>
> 1.03e+n
>
> For any integer n.

You beat me to it.

Step one for mrstephengross is to *rigorously* define what he means by
"significant digits", then go from there. Since I think he mentioned
something about predicting how much space it will take to print out, my
suggestion is to run through whatever printing routines there are and get
a string out, the measure the string, as anything else will likely be
wrong. If that's not possible with the formatting library, you've already
lost; you'll have to completely correctly re-implement the formatting
library, and not only is that a major PITA, you almost never get it
bug-for-bug right...

### Erik Max Francis

May 5, 2005, 4:43:37 PM5/5/05
to
Jeremy Bowers wrote:

> Step one for mrstephengross is to *rigorously* define what he means by
> "significant digits", then go from there. Since I think he mentioned
> something about predicting how much space it will take to print out, my
> suggestion is to run through whatever printing routines there are and get
> a string out, the measure the string, as anything else will likely be
> wrong. If that's not possible with the formatting library, you've already
> lost; you'll have to completely correctly re-implement the formatting
> library, and not only is that a major PITA, you almost never get it
> bug-for-bug right...

Especially since all of his examples have the same number of significant
digits (3), as the term is usually meant. Zeroes to the right are
significant, not zeroes to the left.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
What is it that shapes a species?
-- Louis Wu

### Grant Edwards

May 5, 2005, 10:45:27 PM5/5/05
to
On 2005-05-05, Erik Max Francis <m...@alcyone.com> wrote:

> Especially since all of his examples have the same number of
> significant digits (3), as the term is usually meant. Zeroes
> to the right are significant, not zeroes to the left.

And only the person who performed the measurement knows how
many of the zeros to the right are significant.

--
Grant Edwards grante Yow! They don't hire

### Grant Edwards

May 5, 2005, 10:44:43 PM5/5/05
to
On 2005-05-05, Jeremy Bowers <je...@jerf.org> wrote:

> Since I think he mentioned something about predicting how much
> space it will take to print out, my suggestion is to run
> through whatever printing routines there are and get a string
> out,

A step which will require him to tell the printing routine how
many digits he wants printed.

--
Grant Edwards grante Yow! FUN is never having
at to say you're SUSHI!!
visi.com

### Grant Edwards

May 5, 2005, 10:46:12 PM5/5/05
to
On 2005-05-05, mrstephengross <mrsteph...@hotmail.com> wrote:

No, it isn't. The question is equally meaningless in any
language.

--
Grant Edwards grante Yow! WHO sees a BEACH
at BUNNY sobbing on a SHAG
visi.com RUG?!

### Jeremy Bowers

May 5, 2005, 11:02:06 PM5/5/05
to
On Fri, 06 May 2005 02:44:43 +0000, Grant Edwards wrote:

> On 2005-05-05, Jeremy Bowers <je...@jerf.org> wrote:
>
>> Since I think he mentioned something about predicting how much space it
>> will take to print out, my suggestion is to run through whatever
>> printing routines there are and get a string out,
>
> A step which will require him to tell the printing routine how many digits
> he wants printed.

Not necessarily; consider the str() of a float in Python, especially given
the "significant digits" aspect (it may be ill-defined, but I can think of
several well-defined ways to mean that, where str() embodies one of them).
The easiest way to tell how long the number will be when str prints it out

In C++, this may be harder, as your output software may insist on
rendering everything directly, with no way to reach in and tell what it
did. Imagine the standard IOStreams, without the ability to stream into a
string. Now it's a lot harder to tell. So if you've got something "smart"
like the default str() in Python, you may not be able to tell in advance
what it is going to do, short of trying to manually reverse engineer it.
I've tried that a few times, and in each instance, I can get 95-99%... but
I never quite make it to 100%, usually because I find a bug somewhere and
can't figure out how to characterize and replicate it.

(The biggest of these so far was when I tried to reconstruct Tk's wrapping
in a text widget, so I could tell how many screen lines the given piece of
text I produced would consume, whereupon I discovered Tk didn't correctly
wrap all Unicode characters... it correctly (as far as I could see)
reported their widths, but happily let the characters run right off the
right edge of the widget under certain circumstances I could never
characterize without putting in even more effort than I cared to. The bugs
aren't always *important*, one can imagine the opposite problem of
wrapping a little too quickly, and it could be years before anyone notices
if it's just a few pixels off in the right direction, but it'll still
screw you up if you try to replicate it.)

### Erik Max Francis

May 5, 2005, 11:08:46 PM5/5/05
to
Jeremy Bowers wrote:

> Not necessarily; consider the str() of a float in Python, especially given
> the "significant digits" aspect (it may be ill-defined, but I can think of
> several well-defined ways to mean that, where str() embodies one of them).
> The easiest way to tell how long the number will be when str prints it out
> is to simply ask it.

Grant's point was that as significance is used in scientific studies,
there's no way to answer the question without having the number in
advance. If I say that the length of something is 1100 m, you don't
know whether I mean 1.1 x 10^3 m, 1.10 x 10^3 m, 1.100 x 10^3 m, etc.
These all have different significances. The figure 1100 m can't tell
you how many significance figures are involved without further information.

In particular, the example he gave involved changing significance
depending on the number of zeroes _before_ the other digits, not after
them, which is now how significance works. So obviously when he says
"significant digits" he doesn't mean the same thing that's used by
scientists, so the question can't really be answered.

If he simply wanted to get the number of digits involved, then that's
fine, but that's not what significance is.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis

Eternity is very long, especially near the end.
-- Woody Allen

### Dan Bishop

May 5, 2005, 11:10:09 PM5/5/05
to
Fredrik Lundh wrote:
> "mrstephengross" wrote:
>
> > >But, assuming you have your numbers as strings, I would suggest
> > looking
> > at str.split() and len().
> >
> > Well, the numbers are in fact stored as numbers, so string
processing
> > won't work.
>
> if they're not strings, your question is meaningless. as others have
> pointed out, the exact internal representation for 0.103 is more like
> 0.10299999999999999433786257441170164383947849273681640625
> which has a lot more than 3 digits...

Actually, it's more like

0 01111111011 1010010111100011010100111111011111001110110110010001

### Jeremy Bowers

May 5, 2005, 11:36:05 PM5/5/05
to
On Thu, 05 May 2005 20:08:46 -0700, Erik Max Francis wrote:
> Grant's point was that as significance is used in scientific studies,
> there's no way to answer the question without having the number in

My point was that the original poster never defined "significance" in that
manner, and in the manner in which he seemed to be using the term, my
comments made sense. Which is why the first thing I said was he needs to
rigorously define what he means, and everything after that was predicated
on the assumption he seemed to be looking at consumed screen space.

Message has been deleted

### Fredrik Lundh

May 6, 2005, 2:27:03 AM5/6/05
to pytho...@python.org
Jeremy Bowers wrote:

> > A step which will require him to tell the printing routine how many digits
> > he wants printed.
>
> Not necessarily; consider the str() of a float in Python, especially given
> the "significant digits" aspect (it may be ill-defined, but I can think of
> several well-defined ways to mean that, where str() embodies one of them).
> The easiest way to tell how long the number will be when str prints it out
> is to simply ask it.

and what language is str() implemented in?

> In C++, this may be harder, as your output software may insist on
> rendering everything directly, with no way to reach in and tell what it
> did. Imagine the standard IOStreams, without the ability to stream into a
> string.

but you can stream into a string buffer, and you can use sprintf() from C++,
so what's your point, besides stating that "if things were harder, they would
be harder"?

</F>

### John Roth

May 6, 2005, 9:10:53 AM5/6/05
to
"mrstephengross" <mrsteph...@hotmail.com> wrote in message

> Hi all... How can I find out the number of significant digits (to the
> right of the decimal place, that is) in a double? At least, I *think*
> that's what I'm asking for. For instance:
>
> 0.103 --> 3
> 0.0103 --> 4
> 0.00103 --> 5
> 0.000103 --> 6
> 0.0000103 --> 7
>
> --Steve (mrsteph...@hotmail.com)

As a lot of the responders have pointed out, it's effectively
impossible to do so in any meaningful fashion if all you
have is the binary representation of the number.

One way of doing it is the ScientificDouble class in
PyFit (and in all other versions of FIT, for that matter.)
That provides a class that saves the original string
representation so it can be used to determine precision
for compares. It's a niche approach: it works well for
FIT's purposes, but it's not a general purpose method
of estimating precision throughout a lengthy calculation.
That requires quite different techniques.

See:

fit.c2.com
www.fitnesse.org
FitNesse Yahoo mailing list (see the files section for PyFit.)

John Roth
>

### Jeremy Bowers

May 6, 2005, 12:27:11 PM5/6/05
to
On Fri, 06 May 2005 08:27:03 +0200, Fredrik Lundh wrote:

> Jeremy Bowers wrote:
>
>> > A step which will require him to tell the printing routine how many
>> > digits he wants printed.
>>
>> Not necessarily; consider the str() of a float in Python, especially
>> given the "significant digits" aspect (it may be ill-defined, but I can
>> think of several well-defined ways to mean that, where str() embodies
>> one of them). The easiest way to tell how long the number will be when
>> str prints it out is to simply ask it.
>
> and what language is str() implemented in?

Who cares? It demonstrates the existence of a print routine that prints a
variable number of characters.

>> In C++, this may be harder, as your output software may insist on
>> rendering everything directly, with no way to reach in and tell what it
>> did. Imagine the standard IOStreams, without the ability to stream into
>> a string.
>
> but you can stream into a string buffer, and you can use sprintf() from
> C++, so what's your point, besides stating that "if things were harder,
> they would be harder"?

Giving the original poster the benefit of the doubt, I assumed he was
dealing with some sort of screen library that would render something
without telling him the size, that didn't use streams at all. If that
library also implemented its own pretty print, string streams and
everything else don't help; you need *that* library's pretty print.

May 22, 2005, 10:50:00 PM5/22/05
to
James Stroud wrote:
> Significant digits are an accounting concept. As such, it is up to
the
> accountant to keep track of these as only she knows the precision of
her
> measurements.
>
> Koan for the day:

> What are the significant digits of 0.1?

> Hint:

> >>> 0.1

> James

> On Thursday 05 May 2005 10:37 am, so sayeth mrstephengross:

>> Hi all... How can I find out the number of significant digits (to
the
>> right of the decimal place, that is) in a double? At least, I
*think*
>> that's what I'm asking for. For instance:

>> 0.103 --> 3
>> 0.0103 --> 4
>> 0.00103 --> 5
>> 0.000103 --> 6
>> 0.0000103 --> 7

Since "significant digits" is a representation concept rather
than a mathematical one I'd be inclined to convert the value
to a string, split on the decimal point and return the length
of that.

A naive approach:

def sigdigits(x):
return len( ("%s" % float(x)).split('.')[1])

... but this gives bogus results for integers (saying that they
have "one" significant digit when, by your definition they have
zero.

I suppose you have to amend your definition to handle numbers
larger than 1 and I have to do something different than just
coercing into a float().

def sigdigits(x):
assert float(x) == x # raise an exception if we can't float it
ret = 0
strep = float(x)
(whole, fraction) = strep.split('.')
if int(fraction) > 0:
ret += len(fraction)
if int(whole) > 0:
ret += len(whole)

... I think that should do it. We could explicitly trim leading zeros
from the whole number part and trailing zeros from the fractional
part.
However I think the string representation (in Python's built-ins)
guarantees us that there will be no leading or trailing zeros unless
the part we're looking at is numerically equivalent to zero.

JimD