in reply to How to use the int-function?

Kennethk gave good insight why int is not working as expected (by you). The easiest workaround is to do the rounding yourself, e.g. by
print int ( $j + 0.5);
HTH, Rata

Replies are listed 'Best First'.
Re^2: How to use the int-function?
by Anonymous Monk on Jan 03, 2011 at 15:29 UTC
    Thank you, fellow monks. While two of the above answers pointed out that int is exactly doing what its supposed to do, Rata followed the rather pragmatic approach to show how to actually use the int-function to get the expected result. Let me please try to hold awaken the interest in the practial approach, while peeking into the computer scientist material later.

    In the following view on the problem, I try to round the number 1.255, and try to get the result 1.26. How would you perform this with the typical on-board means, to which undenyingly int() belongs to?

    #!/usr/bin/perl my $i = 1.255; print int($i*100+.5)/100; print "\n";

    Please register, that the same code will do as expected when using "1.355" as value for $i.

      If you are going to be formatting a number for output, I would suggest you use the methods designed specifically to handle that - printf and sprintf. If you are rounding/truncating a value in the context of numerical manipulation, then the approach you take very much depends on your specific needs. There is a very rich field of academic study revolving around performing computations with discrete approximations.

      #!/usr/bin/perl use strict; use warnings; my $i = 1.255; my $j = $i * 100 + 0.5; $j *= 10000000; printf "%.0f\n", $j;

      outputs

      1260000000

        kennethk, I've not yet found that printf would help me with formatting the output:

        perl -e 'printf("%.2f\n", 1.255)'

        -> 1.25

        perl -e 'printf("%.2f\n", 1.455)'

        -> 1.46

        Although, there might be some option which jumps into the gap and helps to round the number?

      Hello there, its me again, the Anonymous Monk! :-)

      Starting a new day, I felt refreshed to wrestle with the rounding problem again. To get to the beef, here is my proposal to round numbers using the int-function:

      #!/usr/bin/perl my $float = $ARGV[0] ? $ARGV[0] : 1.255; my $decimals = $ARGV[1] ? $ARGV[1] : 2; print &round( $float , $decimals ) . "\n"; sub round { my $float = shift; my $decimals = shift; my $int_leftShiftFloat = int( $float * 10**($decimals + 1) ); my $int_Round = int( ( $int_leftShiftFloat + 5 ) / 10 ); my $float_rightShiftInt = $int_Round / 10**$decimals; my $float_Result = $float_rightShiftInt; return $float_Result } sub round_ { my $float = shift; my $dec = shift; return int( ( int( $float * 10**($dec + 1) ) + 5 ) / 10 ) / 10**$dec }
      I've provided to functionally identical versions of the sub, so you may pick up which one is easier for you to read.

      In the long version of the sub, I've tried to use speaking variable names and left out any comments instead.

      To make a general comment on this solution, I've followed the suggestions provided yesterday by my fellow monks, and made the computation using integers to avoid the floating point hassle. What do you think about it?

        A couple comments:
        1. my $decimals = $ARGV[1] ? $ARGV[1] : 2; won't perform as expected if the user enters 0. You will get expected behavior if you use my $decimals = defined $ARGV[1] ? $ARGV[1] : 2;. You should also swap your $float assignment.
        2. On the same point, if you have v5.10 or greater, you can use the 'defined or' operator (//)to do the same thing: my $decimals = $ARGV[1] // 2;
        3. The & is largely unnecessary in modern Perl; your code functions just fine without it.
        4. I'd be a little gun-shy about using the same variable name in the script level variables as in the subroutine level variables - it's easy to introduce a difficult bug.
        5. You can use list assignment rather than a series of shifts if you want to save a few key strokes, replacing

          my $float = shift; my $dec = shift;

          with

            my ($float, $dec) = @_;

          This is almost entirely cosmetic in this context.

        I would also point out your algorithm will still be subject to the whims of these small deviations between string and double precision representation. Consider the default case of:

        #!/usr/bin/perl use strict; use warnings; my $number = defined $ARGV[0] ? $ARGV[0] : 1.2549999999999999; my $places = defined $ARGV[1] ? $ARGV[1] : 2; printf "%.20f\n", $number; print round( $number , $places ), "\n"; sub round { my ($float, $decimals) = @_; my $int_leftShiftFloat = int( $float * 10**($decimals + 1) ); my $int_Round = int( ( $int_leftShiftFloat + 5 ) / 10 ); my $float_rightShiftInt = $int_Round / 10**$decimals; my $float_Result = $float_rightShiftInt; return $float_Result }
        which outputs:

        1.25499999999999990000 1.26