CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
round

 



mike_robb
Novice

Jun 28, 2001, 9:19 AM

Post #1 of 8 (1049 views)
round Can't Post

$x = "123.123456789"

I want $x to contain "123.123"

Is there a round type built in function?

$y=round($x,2) <-- or something similiar??

-TIA!



mike_robb
Novice

Jun 28, 2001, 9:25 AM

Post #2 of 8 (1048 views)
Re: round [In reply to] Can't Post

its not rounding - but this will do... any other idea?

$show_value =~ s/(\d*?\.\d\d\d).*/$1/;



mhx
Enthusiast / Moderator

Jun 28, 2001, 10:18 AM

Post #3 of 8 (1047 views)
Re: round [In reply to] Can't Post

Hi,

use the sprintf function:

Code
$y = sprintf "%.3f", $x;

This does real rounding. If it has to be fast, and your numbers don't get big, and you don't care that it's not rounding:

Code
$y = 0.001 * int( 1000*$x );

But generally, the sprintf thing is better.

-- Marcus



mike_robb
Novice

Jun 28, 2001, 10:51 AM

Post #4 of 8 (1046 views)
Re: round [In reply to] Can't Post

great answer!

thanks.



japhy
Enthusiast

Jun 30, 2001, 6:51 AM

Post #5 of 8 (1037 views)
Re: round [In reply to] Can't Post

Here's a real round() function, and it's faster (and more proper) than sprintf():


Code
sub round { 
my ($num, $places) = @_;
$places ||= 0; # default to rounding to an integer
my $sign = ($num > 0) ? 1 : -1; # pos or neg?

$num *= 10**$places; # shift decimal point
$num = int ($num + .5 * $sign); # add (or subtract) .5, truncate
return $num / 10**$places; # put decimal point back
}

That function can be written much more compactly, but for understanding purposes, I've expanded and commented it. The function takes positive and negative numbers, as well as positive and negative ROUNDING places. A negative rounding place means the decimal point moves to the LEFT first (so round(1234.567,-2) returns 1200).

Jeff "japhy" Pinyan -- accomplished hacker, teacher, lecturer, and author

(This post was edited by japhy on Jun 30, 2001, 12:00 PM)


mhx
Enthusiast / Moderator

Jun 30, 2001, 8:53 AM

Post #6 of 8 (1034 views)
Re: round [In reply to] Can't Post

Hi japhy,

just wanted to tell you there's a typo in your round function. Perhaps the character got lost somewhere, this also happened to me when I posted a regex.

Code
  $num * 10**$places;

should rather be

Code
  $num *= 10**$places;

Anyone can safely ignore the rest of this post. It's based on mislead thoughts and mostly wrong.

I've tried to like the function, but the int made we worry. I thought there were problems with large numbers. But I've tried it, it works very fine. Smile
Anyway, I've looked up int in perlfunc and found:

In Reply To
int EXPR
int
Returns the integer portion of EXPR. If EXPR is omitted, uses `$_'. You should not use this function for rounding: one because it truncates towards `0', and two because machine representations of floating point numbers can sometimes produce counterintuitive results. For example, `int(-6.725/0.025)' produces -268 rather than the correct -269; that's because it's really more like -268.99999999999994315658 instead. Usually, the `sprintf', `printf', or the `POSIX::floor' and `POSIX::ceil' functions will serve you better than will int().

I don't want to justify myself, I don't like the sprintf solution either. Best thing would be if Perl would have such a function built-in. Or we could modify your approach:

Code
use POSIX; 

sub round {
my ($num, $places) = @_;
$places ||= 0; # default to rounding to an integer
my $sign = ($num > 0) ? 1 : -1; # pos or neg?
$num *= 10**$places; # shift decimal point
$num = POSIX::floor($num + .5 * $sign); # add (or subtract) .5, truncate
return $num / 10**$places; # put decimal point back
}

I think that's way better than sprintf, and safer than the int approach.

-- Marcus



(This post was edited by mhx on Jun 30, 2001, 12:18 PM)


japhy
Enthusiast

Jun 30, 2001, 12:59 PM

Post #7 of 8 (1029 views)
Re: round [In reply to] Can't Post

Marcus, you misunderstand the warning in the int() docs. Don't use $x = int($x) to round $x, because it will just truncate the variable to an integer. That is true.

What I do, however, is add (or subtract) .5 to a number, and then truncate it. This is how natural rounding works.


Code
int(1.4 + .5) = int(1.9) = 1 
int(1.7 + .5) = int(2.2) = 2
int(-1.2 - .5) = int(-1.7) = -1
int(-1.9 - .5) = int(-2.4) = -2

If you use either the POSIX::floor or POSIX::ceil functions, you will obtain incorrectly rounded numbers:


Code
floor(1.4 + .5) = floor(1.9) = 1 
floor(1.7 + .5) = floor(2.2) = 2
floor(-1.2 - .5) = floor(-1.7) = -2
floor(-1.9 - .5) = floor(-2.4) = -3

ceil(1.4 + .5) = ceil(1.9) = 2
ceil(1.7 + .5) = ceil(2.2) = 3
ceil(-1.2 - .5) = ceil(-1.7) = -1
ceil(-1.9 - .5) = ceil(-2.4) = -2

My rounding function works because it uses the standard "add .5 and truncate" rounding technique. It also behaves properly for negative numbers.

When the docs said to use the POSIX functions, they meant use one or the other based on the case -- that is, figure out if rounding up or down is needed, and apply the proper function.

Jeff "japhy" Pinyan -- accomplished hacker, teacher, lecturer, and author


mhx
Enthusiast / Moderator

Jun 30, 2001, 1:15 PM

Post #8 of 8 (1028 views)
Re: round [In reply to] Can't Post

Yes, you're right. Thanks. floor() always goes down to the next integer (I should have known that!). I was really mislead there. It also occured to me shortly after my post that your routine doesn't fail. So I'll take most of the stuff out of that post.

When I first saw your round-function the problem I had with the int() function was not what was stated in the perl docs. I thought there could be a problem when numbers get larger than a 'normal integer' (32-bit). But that's not true. Bear with a C-Programmer... ;-)

-- Marcus


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives