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
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |