good chemistry is complicated,and a little bit messy -LW PerlMonks

### Fun with floating points

by kikuchiyo (Monk)
 on Nov 06, 2009 at 13:36 UTC Need Help??

I've got bitten by a peculiarity of floating point handling recently.

The phenomenon is best illustrated with the following snippet:
```\$ perl -le'\$x=0.05;\$y=sqrt(\$x+\$x+\$x);\$g="\$y";print "Is \$y equal to \$g?
+";print \$y==\$g?"Yes":"No"'
Is 0.387298334620742 equal to 0.387298334620742?
No

Of course there is nothing surprising here after all. It should just serve as a reminder that floating point numbers are nasty beasts. It is dangerous to have certain assumptions about them. Also, when you write code that processes a lot of numbers then forms decisions based on comparisons ofthem, it is important to check that the code really does what you think it does. Extreme cases, loss of accuracy and so on.

Replies are listed 'Best First'.
Re: Fun with floating points
by lostjimmy (Chaplain) on Nov 06, 2009 at 17:22 UTC
You should really be comparing floating point numbers using a threshold, rather than an absolute comparison. The problem in your code (correct me if I'm wrong) is that the representation changed when converting from a string back to a float. The following demonstrates a better way to do this.
```my \$x = 0.05;
my \$y = sqrt(\$x+\$x+\$x);
my \$g = "\$y";
my \$h = sprintf "%.20f", \$y;

printf "\\$y = %.20f\n\\$g = %.20f\n", \$y, \$g;
printf "\\$h = %.20f\n", \$h;
print "Is \\$y equal to \\$g? ", floatEqual(\$y, \$g) ? "Yes\n" : "No\n";
print "Is \\$y equal to \\$h? ", \$y == \$h ? "Yes\n" : "No\n";

sub floatEqual {
return (abs(\$_[0] - \$_[1]) <= 10**15);
}

I also added the \$h variable, which works just fine in a direct comparison. I'm sure someone else who knows more about internal representations and conversions can shed more intelligent light on this.

Re: Fun with floating points
by Fox (Pilgrim) on Nov 06, 2009 at 14:23 UTC
I think this is not a problem with float point numbers, but with the comparison operator:
```perl -le'\$x=0.05;\$y=sqrt(\$x+\$x+\$x);\$g="\$y";print "Is \$y equal to \$g?";
+print \$y eq \$g?"Yes":"No"'
Is 0.387298334620742 equal to 0.387298334620742?
Yes
I had a reason to post it as I did.

In the actual application where I had this issue, the workflow was something like this: data was read off from data files and stored in a Storable file. Later, these Storable files were retrieved, and the data in them was further processed. And finally I used a numerical comparison to get the result (is the number dug up from the Storable archives bigger than a pre-specified limit). However, Storable stores floating point numbers as text, at least it did in my application.

So the real issue here is that it is awesomely convenient to have scalars-that-are-both-numbers-and-strings in Perl, but one has to be careful and know that it may lead to strange results sometimes.
String/float conversion is not the only problem while dealing with floats. Consider following example:
```perl -e '\$x=1/3; \$x-=1/2; \$x+=1/3; \$x-=1/2; \$x+=1/3; print \$x,"\n"'
\$x should be equal to zero but it isn't.

Create A New User
Node Status?
node history
Node Type: perlmeditation [id://805476]
Approved by moritz
Front-paged by Arunbear
help
Chatterbox?
 [ambrus]: Corion: I think I parsed a HTTP header from a string with LWP once. You can definitely use that to create a HTTP message too. The problme is [ambrus]: that if you do that, you'd have to find where each HTTP response ends, which is nontrivial if you want persistent connections (essential for performance if you have small requests). [Corion]: ambrus: Yes, ideally an API that I feed the incoming data piece by piece and that I can ask "is that response done" and "what should I do next" and "please construct the appropriate redirect for me" [Corion]: ambrus: Yes, ideally the module would do all that nasty stuff for me and give me a way to ask it what the current situation is [ambrus]: Corion: you could also consider using some wrapper over the multi interface of curl, I think Net::Curl might be a good one, since implementing enough of what it expects from the event loop might be easier than a full AnyEvent interface. [ambrus]: Corion: you could also consider using IO::Async and its POE driver and some HTTP module for it, but I don't know if that would solve your problems with AnyEvent+POE [ambrus]: Corion: wait, you didn't say POE. You said Prima, let me look up what that is. [ambrus]: Corion: have you considered just writing an AnyEvent integration for that thing? [ambrus]: Or perhaps pushing schmorp to write one? [ambrus]: Also, searching for an existing one on CPAN obviously

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (16)
As of 2016-12-07 16:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
On a regular basis, I'm most likely to spy upon:

Results (130 votes). Check out past polls.