That's a fairly contrived example. The better_average loses here because of compounded errors in float division. I tried using random numbers instead, and I found them more or less equivalent.

use Math::BigFloat; my %score_for; my $loops = 100; my $step = 500; my $inputs = 100_000; foreach my $i ( 1 .. $loops ) { my $n = $i * $step; my @input = map { rand $n } 1 .. $inputs; my $correct = perfect_average( @input ); my $bad = bad_average( @input ); my $better = better_average( @input ); my $bad_diff = $correct->copy()->bsub( $bad )->babs(); my $better_diff = $correct->copy()->bsub( $better )->babs(); my $cmp = $bad_diff->bcmp( $better_diff ); my $winner = ( $cmp > 0 ) ? 'bad' : ( $cmp < 0 ) ? 'better' : 'tie +'; push @{$score_for{ $winner }}, $n; print "n: $n, winner: $winner\n"; } foreach my $method ( qw( bad better tie ) ) { my $score = scalar @{$score_for{ $method }}; my $avg = int perfect_average( @{$score_for{ $method }} ); print "'$method' won $score (avg $avg)\n"; } sub perfect_average { my $acc = Math::BigFloat->new(); $acc->badd( $_ ) for @_; $acc->bdiv( scalar @_ ); return $acc; } sub bad_average { my $acc = 0; $acc += $_ for @_; return $acc / @_; } sub better_average { my $acc = 0; $acc += $_/@_ for @_; return $acc; }

(As an aside, it occurs to me that I could have written "( $cmp > 0 ) ? 'bad' : ( $cmp < 0 ) ? 'better' : 'tie';" as "('tie', 'bad', 'better')[$cmp]" if $cmp is 0, 1, or -1. That seems pretty obscure, though.)

I've fooled with the various knobs a bit, and what seems to be true is that "bad" and "better" win about evenly. I thought maybe one would be better for large numbers than the other, but I haven't found that either.

I should note that this is my first use of Math::BigFloat, so it's entirely possible my entire test is bogus. Still, I think this is a better test of each algorithm than pumping them full of ones.


In reply to Re^3: Floating Point Errors: How and Why to Avoid Adding and Subtracting Varying Numbers by kyle
in thread Floating Point Errors by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.