How to detect a double's significant digits

G

Grant Edwards

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.

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

Jeremy Bowers

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.

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.)
 
E

Erik Max Francis

Jeremy said:
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.
 
D

Dan Bishop

Fredrik said:
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
 
J

Jeremy Bowers

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.

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

Dennis Lee Bieber

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.
There isn't any method (except maybe in Ada using "fixed" not
"float" data types).

Consider (using decimal as I don't want to compute the binary
equivalents)...

10.04
1.004

are handled internally as

1.004 E1
1.004 E0

--
 
F

Fredrik Lundh

Jeremy said:
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>
 
J

John Roth

mrstephengross said:
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

Thanks in advance!
--Steve ([email protected])

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
 
J

Jeremy Bowers

and what language is str() implemented in?

Who cares? It demonstrates the existence of a print routine that prints a
variable number of characters.
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.
 
A

AnswerGuy

James said:
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?

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top