What would be a good round() function that "rounds-to-nearest-even"?
Would using sprintf in this function slow it down?
sprintf is surprisingly fast. I wrote a little benchmark program (see
below) with a mathetically correct (round to nearest, round to even on
tie), two "naive" implementations and sprintf (which is also correct on
my machine). As expected, the correct version is the slowest. But
sprintf is not only the fastest, it is almost twice as fast as the next
one:
nearest_even: 47.640588
naive_floor: 27.722728
naive_int: 34.791525
sprintf: 18.669429
Is there any chance such a function could be included as a built-in
function in a future Perl?
A round() function written C (or assembler) could be quite a bit faster
than sprintf. But whether that makes a real difference depends on the
time your program spends rounding.
#!/usr/bin/perl
use warnings;
use strict;
use Time::HiRes qw(time);
use POSIX qw(floor);
{
sub nearest_even {
my $x = $_[0];
my $f = floor($x);
return $x - $f < 0.5 ? $f :
$x - $f > 0.5 ? $f + 1 :
$f % 2 == 0 ? $f :
$f + 1 ;
}
my $t0 = time;
for (my $x = -1_000_000; $x <= 1_000_000; $x += 0.0625) {
my $y = nearest_even($x);
# print "$x -> $y\n";
}
printf "nearest_even: %f\n", time - $t0;
}
{
sub naive_floor {
return floor($_[0] + 0.5);
}
my $t0 = time;
for (my $x = -1_000_000; $x <= 1_000_000; $x += 0.0625) {
my $y = naive_floor($x);
# print "$x -> $y\n";
}
printf "naive_floor: %f\n", time - $t0;
}
{
sub naive_int {
my $x = shift;
return $x >= 0 ? int($x + 0.5) : int($x - 0.5);
}
my $t0 = time;
for (my $x = -1_000_000; $x <= 1_000_000; $x += 0.0625) {
my $y = naive_int($x);
# print "$x -> $y\n";
}
printf "naive_int: %f\n", time - $t0;
}
{
my $t0 = time;
for (my $x = -1_000_000; $x <= 1_000_000; $x += 0.0625) {
my $y = sprintf("%.0f", $x);
# print "$x -> $y\n";
}
printf "sprintf: %f\n", time - $t0;
}
__END__
hp