last_stand has asked for the wisdom of the Perl Monks concerning the following question:

I am a bit perplexed about the way the way int is behaving in my code. I am trying to read integer data from an XML for further use. the code reads the tagged data properly but when I convert in any data(which I already know is an integer)into an int then the value reduces by one.Also this behaviour is exibited only for certain numbers like 255 or 65535. Can anyone explain why and how this is happening.

Replies are listed 'Best First'.
Re: int's behaviour
by tachyon-II (Chaplain) on Nov 24, 2007 at 23:54 UTC

    As swampyankee points out it would appear that although you think you have an integer, in fact you have a floating point number as the internal representation so your 255 is stored as 254.999999 which when you apply int to it gets truncated and results in the behaviour described. Using sprintf instead of int will probably behave as you desire.

    $i = sprintf "%.0f", 254.99; print "$i\n"; # printf/sprintf rounds rather than truncates using %f # however %d works just like int() printf "Number %.3f int %d sprintf %.0f\n",$_/7,$_/7,$_/7 for 1..100;

    I recommend My floating point comparison does not work. Why ? and particularly the article What Every Scientist Should Know About Floating-Point Arithmetic

      That's a good suggestion, but beware that sprintf uses the round-to-even method of rounding.

      $ perl -e 'printf "%.0f\n", 2.5;' 2 $ perl -e 'printf "%.0f\n", 1.5;' 2

      To get the usual "round up" method, I usually use int with the value plus a half.

      $ perl -le '$x=1.5;print int($x+.5)'; 2 $ perl -le '$x=2.5;print int($x+.5)'; 3
Re: int's behaviour
by swampyankee (Parson) on Nov 24, 2007 at 23:11 UTC

    Your data aren't integers; they've values like 254.99, and int truncates; it doesn't round. In addition to showing the code, you're going to have to show the offending data, too.


    emc

    Information about American English usage here and here.

    Any Northeastern US area jobs? I'm currently unemployed.

Re: int's behaviour
by BrowserUk (Patriarch) on Nov 24, 2007 at 22:07 UTC

    You'll almost certainly have to show us what you are doing in the extraction before we can offer any kind of explaination or workaround. Like pictures, the code paints a thousand words.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: int's behaviour
by GrandFather (Saint) on Nov 24, 2007 at 22:29 UTC

    Show us the dozen lines of code in a runnable sample required to reproduce the problem (including the one short line of XML data).

    Tell us what you see output by the code and what you expected to see, otherwise our best advice to you is to adjust the plimwobble parameter on the frobtizit transform.

    Oh, and remember to use strictures (use strict; use warnings;).


    Perl is environmentally friendly - it saves trees
Re: int's behaviour
by KurtSchwind (Chaplain) on Nov 24, 2007 at 22:09 UTC

    When you say that it reduces by one those values, do you mean that if you read in 255 you get 254? Or is it if you read in 256 you get 255?

    You could help us out a great deal with a code snippet and a data snippet so we can see what you are talking about.

    --
    I used to drive a Heisenbergmobile, but every time I looked at the speedometer, I got lost.
Re: int's behaviour
by ikegami (Patriarch) on Nov 25, 2007 at 18:49 UTC
    Just like there are periodic numbers in decimal (1/3), there are periodic numbers in binary (1/10). To store those numbers as a decimal number (like floats do) would require infinite storage, so some error is introduced into those numbers when storing them in floats. I suspect your problem lies such those numbers. Here are two examples
    >perl -le"print substr +(reverse unpack 'B*', pack 'd', shift), 12" .1 1101100110011001100110011001100110011001100101011001 ^^^^ period >perl -le"printf '%.16e', shift" .1 1.0000000000000001e-001 ^ error

    The error isn't always obvious at first since the system does a little bit of rounding automatically, but some errors can easily be noticed when the error is compounded through addition.

    >perl -le"$x=.1; $n=$x*100; print int $n" 10 >perl -le"$x=.1; $n+=$x for 1..100; print int $n" 9

    Note: reverse is needed on x86 machines since they store floats in little-endian order.

Re: int's behaviour
by Anonymous Monk on Nov 25, 2007 at 03:59 UTC
    try:
    sub round { map{ int($_ + 0.5) @_ }
      I am putting the code:: i am using following function to figure out range of a variable.. $range_data= find_range($max_data,$min_data,$step_data); I am passing the max value, min value and resolution. The function would return the range. the function definition is::
      sub find_range { my $max=$_[0]; my $min=$_[1]; my $step=$_[2]; my @step_part; my $range; $range=($max-$min)/($step_real); return($range); }
      now when I do: $range_int= int($range_data); and try to print range_data and range_int i get different values.specifically 65535 becomes 65534 and 255 becomes 254. Also I know range_data is 65535 and not 65534.99 . Can anyone help me.

        Either the code you posted is not the code you are using or you should be using the strict pragma. You are initializing a variable $step but you are dividing by a variable $step_real.

        Also, please post a complete, self-contained, short program that demonstrates the issue. You talk about variables with names like range_data and range_int but never show how and where they are used.