use strict; use warnings; ######## # This version takes two arguments # The number to round # And the number of places to the right or left of the decimal point # Positive numbers to the left, negative numbers to the right. # Think powers of 10. # # Parts of this were stolen from nodeid=8781, and nodeid=1873 # most notably from Roy Johnson and wrvhage ######## sub round { my ($number, $places) = @_; my $sign = ($number < 0) ? '-' : ''; my $abs = abs($number); if($places < 0) { $places *= -1; return $sign . substr($abs+("0." . "0" x $places . "5"), 0, $places+length(int($abs))+1); } else { my $p10 = 10**$places; return $sign . int($abs/$p10 + 0.5)*$p10; } } ######## # Simple Ceiling function ######## sub ceil { my ($num) = @_; return int($num) + ($num > int($num)); } ######## # Function modeled after Excel's two argument function # Number to act on # Interval to return (2 would return only multiples of 2, 3 multiples of 3 etc) ######## sub ceil_xl { my ($num,$interval) = @_; return ceil($num / $interval) * $interval; } ######## # Function derived from node_id=270920 # Returns next nearest mulitple of 5 up to 50, then nearest 25 up to 100, # then nearest quarter of current power of 10. ######## sub ceil_qtrs { my ($num) = @_; my $abs=int(abs($num)); my $interval; # This next line was the originally given answer from Abigail-II, # it was obtuse enough that I needed to break it down to fully understand it, # then I wanted to modify it, and I then left my version in the more readable # style. # my $frac = $num < 100 ? 5 : (1 . ("0" x (length ($num) - 1))) / 4; if($abs < 40) { $interval = 5; } elsif($abs < 100) { $interval = 25; } else { $interval = "1".("0"x(length($abs)-1)); $interval = $interval/4; } return ceil($num / $interval) * $interval; } my @data = qw(1 2 3.14159 4.634 5 5.165 6 9 10 10.257 13 23 89 99 100 101 214 702 1328 -1 -2 -3.14159 -4.634 -5 -5.165 -6 -9 -10 -10.257 -13 -23 -89 -99 -100 -101 -214 -704 -1328 ); my $format = " "."%13.13s "x8 . "\n"; printf ($format, "number","ceil_qtrs","ceil_xl(x,3)","ceil_xl(x,8)","ceil(x)","round(x,0)","round(x,1)","round(x,-2)"); foreach (@data) { printf ("%13.13s ",$_); printf ("%13d ",ceil_qtrs($_)); printf ("%13d ",ceil_xl($_,3)); printf ("%13d ",ceil_xl($_,8)); printf ("%13d ",ceil($_)); printf ("%13d ",round($_,0)); printf ("%13d ",round($_,1)); printf ("%13.3f ",round($_,-2)); print "\n"; }