Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

simple precision question

2 views
Skip to first unread message

David Staschover

unread,
Jan 20, 1995, 3:56:47 PM1/20/95
to
Hi,

Can someone tell me why:

print 9.95*1;

produces 9.9499999999999992895 ?

I know BASIC has that problem, (and so do pentiums :)..

Can i fix this without having to use formatted prints?

Thanks,

David Staschover

=======================================================================
David Staschover | d...@panix.com | http://www.webscope.com
Stelcom, Inc. | da...@stelcom.com | The Webscope Commercial Center
Tel: 516-897-8168 | ste...@aol.com | "The World Wide Web --
Fax: 516-897-3793 | | the medium for the 90's"
=======================================================================

Hans Mulder

unread,
Jan 23, 1995, 10:44:57 AM1/23/95
to
In <3fp82f$2...@panix.com> d...@panix.com (David Staschover) writes:

>Can someone tell me why:

> print 9.95*1;

>produces 9.9499999999999992895 ?

Because 9.95 cannot be represented exacly in binary.

>I know BASIC has that problem, (and so do pentiums :)..

All binary computers have this problem; it doesn't
matter what language you use.

>Can i fix this without having to use formatted prints?

Setting

$# = '%.3g';

forces numbers to be rounded to two decimal places whenever
they're converted to strings. Use of $# is deprecated, though.

If you're dealing with money, consider using the cent as the
fundamental unit and

use integer;

if you have perl5.

--
Hope this helps,

HansM

Mark A Biggar

unread,
Jan 23, 1995, 5:23:44 PM1/23/95
to
In article <3fp82f$2...@panix.com> d...@panix.com (David Staschover) writes:
>Can someone tell me why:
> print 9.95*1;
>produces 9.9499999999999992895 ?
>I know BASIC has that problem, (and so do pentiums :)..

First off notice that:

print 9.95;

displays exactly the same thing. The problem is that 9.95 cannot be
represented exactly in binary floating point (the actual binary fractional
part has an infinite repeating expansion, just like 1/3 = .33333... in
decimal). The value printed out is the closest your hardware can come
to representing the value you asked for.

>Can i fix this without having to use formatted prints?

No.

--
Perl's Maternal Uncle
Mark Biggar
m...@wdl.loral.com


Larry Wall

unread,
Jan 24, 1995, 12:35:39 PM1/24/95
to
In article <3fp82f$2...@panix.com> d...@panix.com (David Staschover) writes:
: Hi,

:
: Can someone tell me why:
:
: print 9.95*1;
:
: produces 9.9499999999999992895 ?
:
: I know BASIC has that problem, (and so do pentiums :)..
:
: Can i fix this without having to use formatted prints?

Well, Perl 5 will print that as 9.95, not because it's keeping the
number any more precisely, but because Perl 5 has a better idea how
many digits of precision it should ask printf for internally. But in
general, if you want a particular precision on floating point numbers,
you have to use printf or sprintf.

Perl doesn't try to impose a particular model on the numerical operations
of your machine. There are languages that do so (REXX comes to mind),
but these languages pay for this in increased overhead. I might well
have made a similar decision twenty years ago, but the IEEE has been
doing a pretty good job at defining how floating point should work,
so it turned out to be the right thing (usually) for Perl to go with the
built-in semantics provided by the system.

This means that your programs run faster, but also that you must
understand the limitations of floating point. The foremost of these
limitations is that there is no exact representation of most decimal
fractions. This means that you should either a) store all your money
in integer cents rather than fractional dollars (or whatever your
cultural equivalent is) or b) satisfy yourself that the errors don't
add up (or multiply!) to anything significant, and then be careful to
print with only the precision you desire, using printf(), which rounds,
and not int(), which truncates.

The integer method is best for those who are truly paranoid about missing
a penny or two, but for ordinary purposes the live-with-the-errors
approach seems to work out fine in practice. (This wasn't so in the
days of single-precision, but Perl does everything in double precision,
and you have add a LOT of numbers to get the errors to grow 13 orders
of magnitude. (Multiplication and division are a different story, of
course.))

Life teaches us that there's no correlation between simple questions
and simple answers.

Larry

Paul Eggert

unread,
Jan 24, 1995, 8:35:40 PM1/24/95
to
lw...@netlabs.com (Larry Wall) writes:

> Perl 5 will print that as 9.95, not because it's keeping the
> number any more precisely, but because Perl 5 has a better idea how
> many digits of precision it should ask printf for internally.

Larry is suppressing some details to get on with his story, but I can't resist
turning over a corner of the rug to show what's crawling underneath.

It is trickier than you might expect to read and print 9.95, since IEEE
double precision floating point cannot represent 9.95 exactly;
it approximates it with the closest number that it can represent exactly,
namely 9.949999999999999289457264239899814128875732421875.

However, you _can_ print the minimum number of digits such that if you
later reread the digits, you are guaranteed to get the same number that
was printed. If your C library is written properly (most aren't, but a
few are, e.g. Solaris 2.x), then you're guaranteed to get output that
is both brief and accurate with Perl 5. Even if your C library is a
little looser, you should usually luck out and get `9.95' with perl 5;
but there will be other examples where you don't luck out.

You might be surprised (I was!) that it wasn't commonly known how to
read and print floating point numbers accurately, in the sense
described above, until 1990; this is partly why many libraries do the wrong
thing in this area. Please see the following references for details.

William D Clinger, How to read floating-point numbers
accurately. SIGPLAN notices 25, 6 (June 1990), 92-101.

Guy L Steele Jr and Jon L White, How to print floating-point
numbers accurately. SIGPLAN notices 25, 6 (June 1990), 112-126.

Keith Thompson

unread,
Jan 28, 1995, 3:47:06 AM1/28/95
to
In <3g0itp$s...@wsinti05.win.tue.nl> ha...@wsinti05.win.tue.nl (Hans Mulder) writes:
> In <3fp82f$2...@panix.com> d...@panix.com (David Staschover) writes:
> >Can someone tell me why:
>
> > print 9.95*1;
>
> >produces 9.9499999999999992895 ?
>
> Because 9.95 cannot be represented exacly in binary.

That's part of the problem, but not all of it; there's also a bug in
Perl 4. Internally, the number 9.95 is represented as a floating-point
number of type double (typically 64-bit IEEE floating-point). The print
function uses C's printf() with a default format (as of Perl 4) of
'%.20g'. The problem is that 20 decimal digits is substantially more
precision than can be represented by a double, which is why you see the
extra garbage digits at the end.

As of Perl 5, the default format has been changed to '%.15g', so this
problem no long occurs; the value 9.95 still isn't represented exactly,
but it's now rounded properly for output.

> >Can i fix this without having to use formatted prints?
>
> Setting
>
> $# = '%.3g';
>
> forces numbers to be rounded to two decimal places whenever
> they're converted to strings. Use of $# is deprecated, though.

Right. Don't use $#; it behavior has changed in Perl 5, so it's a bit
non-portable anyway. If you can, upgrade to Perl 5. Another option is
to use printf explicitly, which gives you control over the output format.

--
Keith Thompson (The_Other_Keith) k...@thomsoft.com (k...@alsys.com still works)
TeleSoft^H^H^H^H^H^H^H^H Alsys^H^H^H^H^H Thomson Software Products
10251 Vista Sorrento Parkway, Suite 300, San Diego, CA, USA, 92121-2718
When you're a nail, every problem looks like a hammer.

Paul Eggert

unread,
Feb 2, 1995, 11:09:18 PM2/2/95
to
k...@alsys.com (Keith Thompson) writes:

> As of Perl 5, the default format has been changed to '%.15g', so this
> problem no long occurs; the value 9.95 still isn't represented exactly,
> but it's now rounded properly for output.

But %.15g doesn't ``round properly'', because it loses information on output.
Perl's default should be to print a floating point number
so that when you read it back in, you get the same number.

Here is an example of the problem. If $x is a number, then the comparison

$x.'' == x

should always succeed, since it merely converts $x to a string and
then back to a number. But it doesn't always work! E.g. (assuming
the typical case of IEEE floating point):

$x = 1.000000000000004;
if ($x.'' != $x) { print "BAD\n"; }

prints "BAD", because $x contains the IEEE double value
1.000000000000003996802888650563545525074005126953125, and when $x is
converted to a string using that %.15g format, it is converted to plain "1".
Since $x != 1 the result is BAD.

It turns out that 15 digits do not suffice for IEEE double precision;
you must use exactly 17 digits, no more and no less. The number 17 is
specified by the IEEE floating point standard itself; see
ANSI/IEEE Std 754-1985 section 5.6 (page 12 line 20).

The problem is that perl uses DBL_DIG to decide how many digits to
print. This is incorrect. DBL_DIG does not specify the minimum
number of digits needed to represent a floating point number
unambiguously, which is what Perl should be using. Instead, DBL_DIG
specifies the maximum number of digits that can be converted to float
without losing information; this is normally a smaller number (unless
we are using a base 10 floating point representation).

I just noticed this problem. I'll send a bug report and a patch to
perl5-porters.

Keith Thompson

unread,
Feb 5, 1995, 4:35:42 AM2/5/95
to
I wrote:
> As of Perl 5, the default format has been changed to '%.15g', so this
> problem no long occurs; the value 9.95 still isn't represented exactly,
> but it's now rounded properly for output.

In response to which egg...@twinsun.com (Paul Eggert) wrote:
> But %.15g doesn't ``round properly'', because it loses information on output.
> Perl's default should be to print a floating point number
> so that when you read it back in, you get the same number.

[...]


> It turns out that 15 digits do not suffice for IEEE double precision;
> you must use exactly 17 digits, no more and no less. The number 17 is
> specified by the IEEE floating point standard itself; see
> ANSI/IEEE Std 754-1985 section 5.6 (page 12 line 20).

[...]


> I just noticed this problem. I'll send a bug report and a patch to
> perl5-porters.

Hmmm. I see your point, but I'm not sure I agree. The advantage of
using 17 digits, as you pointed out, is that converting from double to
string and back again doesn't lose information. The disadvantage is that
it often results in ugly output.

For example, if the next version of Perl uses a default format of '%.17g',
the statement

print "This is Perl version $]\n";

will print

This is Perl version 5.0010000000000003

I'm tempted to suggest a new built-in function that returns an unambiguous
string representation of a number, but it's easy enough to write your own:

sub double_to_string {
# Assumes IEEE double-precision floating-point
return sprintf '%.17g', @_;
}

For most uses (printing reports, etc.), I think Perl 5.000's current
behavior is adequate. As long as it's possible to get either behavior
via an explicit [s]printf, I think avoiding ugly output is more important
than squeezing out those last few bits of precision.

Paul Eggert

unread,
Feb 15, 1995, 11:37:09 PM2/15/95
to
k...@alsys.com (Keith Thompson) writes:

> As long as it's possible to get either behavior
> via an explicit [s]printf, I think avoiding ugly output is more important
> than squeezing out those last few bits of precision.

Yes, but the two choices are not mutually exclusive.
There are algorithms that do both -- that is, they avoid ugly output
with numbers like 5.0001, _and_ they never lose information.

I sent off a patch to perl5-porters that uses a
crude-and-simple-but-reliable algorithm that has this property.
There's also a much more elegant (and presumably more efficient) algorithm
(see below) that perhaps some nice volunteer could hack into perl.

(The rest of this message is a quote from mail
that I recently sent to the perl5-porters list on this subject.)

See Guy L Steele Jr and Jon L White, How to print floating-point
numbers accurately, SIGPLAN notices 25, 6 (June 1990), 112-126.
Sample quote:

Isn't it a pain when you ask a computer to divide 1.0 by 10.0
and it prints 0.0999999? Most often the arithmetic is not to
blame, but the printing algorithm [is].

An algorithm like Steele and White's is required of Scheme implementations;
see IEEE Std 1178-1990 section 6.5.6 (Numerical Input and Output),
which requires that printing a floating-point number in base 10
write the minimum number of digits such that reading the digits
gives you the original number.

Not that I'm a Scheme fanatic, but perl should be just as good as
Scheme in this respect anyway. Maybe you can steal the ideas from
your nearest working Scheme implementation. See, for example,
<ftp://swiss-ftp.ai.mit.edu:/archive/scheme-7.3/src.tar.gz>;
look in the file src/runtime/dragon4.scm for an implementation of the
Steele-White algorithm.

0 new messages