 Perl Monk, Perl Meditation PerlMonks

Re: How do I round a number?

by 5mi11er (Deacon)
 on Apr 27, 2005 at 16:54 UTC ( #452025=note: print w/replies, xml ) Need Help??

in reply to How do I round a number?

I was looking for a ceil(x,y) function similar to what exists in excel, where x is the thing to round, and y is "significance" according to Excel v9 (Office 2000), I prefer to think of it as "interval".

But, I was also intrigued by several of the other answers given (found via supersearch), and then in a fit of playing around, I created several variations below.

My personal restrictions were to use math operations, and not rely on other modules. This eliminated the printf and POSIX answers.

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 poin +t # 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 multipl +es 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 t +o 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 unders +tand 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)","c +eil(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"; }

Replies are listed 'Best First'.
Re: Answer: How do I round a number?
by Roy Johnson (Monsignor) on Apr 27, 2005 at 17:56 UTC

Caution: Contents may have been coded under pressure.
Wow, that's quite a scratchpad, thanks.

So, I hadn't thought much about negative numbers. Is it mathematically correct for the ceiling function to go to the next more negative number (to the left on a number line) or to truncate (ie int) a negative number (move toward the right on a number line)?

I think the rounding functions for negative numbers are correct (don't need adjusting), you're simply moving toward the nearest whole number...

-Scott

Update: As further discussed below, the code did originally have issues, the code in the answer above has now been replaced by working code.

ceil should always round toward the right on a number line, so your ceil is correct. In fact, it's the same thing I came up with in Re^2: Perl oddities. Note merlyn's response, though.

Caution: Contents may have been coded under pressure.

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://452025]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (6)
As of 2022-01-19 20:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
In 2022, my preferred method to securely store passwords is:

Results (56 votes). Check out past polls.

Notices?