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"; }