for; while loop interations

Discussion in 'Perl Misc' started by Jayaprakash Rudraraju, Sep 23, 2003.

  1. Hi,

    The following two snippets of code are iterating the while loop same
    number of times. I am not able to comprehend the reason. Thanks in advance
    for your explanations.

    $intv = 1.1;
    while ($intv > 0.4) {
    print "$intv\n";
    $intv -= 0.1
    }

    $intv = 1.1;
    while ($intv >= 0.4) {
    print "$intv\n";
    $intv -= 0.1
    }

    Prakash
    --
    94.5% of all statistics are made up.
    Jayaprakash Rudraraju, Sep 23, 2003
    #1
    1. Advertising

  2. Jayaprakash Rudraraju wrote:
    >
    > Hi,
    >
    > The following two snippets of code are iterating the while loop same
    > number of times. I am not able to comprehend the reason. Thanks in advance
    > for your explanations.
    >
    > $intv = 1.1;
    > while ($intv > 0.4) {
    > print "$intv\n";
    > $intv -= 0.1
    > }
    >
    > $intv = 1.1;
    > while ($intv >= 0.4) {
    > print "$intv\n";
    > $intv -= 0.1
    > }


    Try changing the statement:

    print "$intv\n";

    To:

    printf "%.20f\n", $intv;

    And see what happens.

    perldoc -q numbers

    Found in /usr/lib/perl5/5.6.0/pod/perlfaq4.pod
    Why am I getting long decimals (eg, 19.9499999999999)
    instead of the numbers I should be getting (eg, 19.95)?



    John
    --
    use Perl;
    program
    fulfillment
    John W. Krahn, Sep 23, 2003
    #2
    1. Advertising

  3. Jayaprakash Rudraraju

    Eric Bohlman Guest

    Jayaprakash Rudraraju <> wrote in
    news:p:

    >
    > Hi,
    >
    > The following two snippets of code are iterating the while loop same
    > number of times. I am not able to comprehend the reason. Thanks in
    > advance for your explanations.
    >
    > $intv = 1.1;
    > while ($intv > 0.4) {
    > print "$intv\n";
    > $intv -= 0.1
    > }
    >
    > $intv = 1.1;
    > while ($intv >= 0.4) {
    > print "$intv\n";
    > $intv -= 0.1
    > }


    Never use fractional floating-point values as loop counts, or in any other
    case where an exact comparison is required. This is actually a basic
    principle of computing, independent of what programming language you're
    using. Your problem here is that 0.1 doesn't have an exact representation
    as a binary fraction, just as 1/3 doesn't have an exact representation as a
    (finite length) decimal fraction.

    The basic rule here is that floating-point numbers are not real numbers in
    the mathematical sense and cannot be expected to behave like them (for
    example, floating-point addition is not always associative). There's a
    whole branch of mathematics, numerical analysis, that's devoted to finding
    ways to minimize the effects of this unpleasant truth.
    Eric Bohlman, Sep 23, 2003
    #3
  4. On Mon, 22 Sep 2003 21:00:33 -0700, Jayaprakash Rudraraju <> wrote:

    >
    >Hi,
    >
    >The following two snippets of code are iterating the while loop same
    >number of times. I am not able to comprehend the reason. Thanks in advance
    >for your explanations.
    >
    >$intv = 1.1;
    >while ($intv > 0.4) {
    > print "$intv\n";
    > $intv -= 0.1
    >}
    >
    >$intv = 1.1;
    >while ($intv >= 0.4) {
    > print "$intv\n";
    > $intv -= 0.1
    >}


    Hi,

    I think you'll see what is going on easily if you try to
    work out what 1/10 is in binary.

    Floating point is not a precise way of dealing with values.
    Whatever the number of bits used to store the FP values it
    is a fixed number and so you are mapping infinite set of rational
    numbers (a/b ) into a finite space and the result is that there
    are "holes" (some, actually infinitely many, rationals get lost).

    This ends up giving you a type of arithmetic that has some very
    strange properties; rather like the moire patterns that appear
    if you draw a lot of lines on a computer screen because those
    lines aren't really straight they're a sequence of dots approximating
    where the line would be if you could draw it. That's what you're
    witnessing here, if you want 100% accuracy you have to use integer
    methods eg;

    (no code tested)

    (i) integer scaling
    ~~~~~~~~~~~~~~~~~~~

    $intv = 11;
    while ($intv > 4) {
    print $intv/10."\n"; # print approximation of intv/10
    # for exact display use string splicing
    $intv -= 1;
    }

    $intv = 11;
    while ($intv >= 4) {
    print $intv/10."\n"; # print approximation of intv/10
    # for exact display use string splicing
    $intv -= 1;
    }

    (ii) integer/modulus(=fixed=10)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    $intv = 1; $modv= 1;
    while ($intv*10+$modv > 4) {
    print $intv.".".$modv."\n";
    if( ($modv -= 1) < 0)
    {
    $intv -= 1; $modv += 10;
    }
    }
    }

    $intv = 1; $modv = 1;
    while ($intv*10+$modv >= 4) {
    print $intv.".".$modv."\n";
    if( $modv -= 1 < 0)
    {
    $intv -= 1; $modv += 10;
    }
    }
    }

    (i) & (ii) should do for most uses where you only need a fixed
    precision, really you are just translating everything directly
    into integers,

    (iii) integer/modulus(=variable=MODU)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Just change 10 in the above for $MODU
    You can even keep a seperate MODU value for each value you use
    and write some functions to perform operations on these type
    of values (intv,modv,MODU) == intv+modv/MODU

    So this will in theory be able to deal with rational numbers
    in the way we would expect them to behave.

    Of course the problem is that MODU can and will grow arbitarily
    large and really you need some "clean-up" function to reduce
    modv/MODU (finding any common factor and dividing) just to make
    sure it doesn't become unneccesarily large at a given time.

    You won't be able to calculate square roots and sines, cosines, etc
    in most cases because it is not possible to do that (they don't
    produce rational numbers in a lot of cases so you aren't actually
    calculating them when you do $a=sqrt($b); it is an approximation
    of course the problem with FP is that it doesn't exactly come
    screaming in your face that $a=$b/$c migth be an approximation or
    that $a=$b+$c can introduce errors!)

    The time to calculate an operation will increase with the complexity
    of the number until eventually it takes ages and megabytes of workspace
    and of course at some point the system won't have the resources to
    deal with it anymore ( before that you have to write a function
    or get a perl module to deal with arbitarily large integers)

    Usually when people utilise floating point it is because the
    loss in accuracy doesn't matter (because it is a leisure application
    maybe). A thing to be wary of is belief that using some very
    high precision FP will somehow increase the overall accuracy of
    the math - each time you perform an operation on a value in FP
    you are on average introducting more error into it, and this error
    will rapidly get larger the more operations you perform, as it
    propagates. If you are doing some repeated operation you can say byebye
    to any hint of mathematical accuracy over time and the FP size won't
    have much effect on this. If it is an application where the accuracy is of
    any importance (aside from cosmetic) then either (i) calculate possible
    error bounds (I don't know if there are studies on this but it seems
    very difficult because you have to factor in every single operation
    and often won't even know the size of the FP given that your program
    may run in different environments) (ii) use integer methods

    Just the other day I was using something called 'mogrify' to produce some
    thumbnails for a new website gallery and I noticed that the scaling method
    it uses is obviously the incorrect FP method because every other picture
    was losing 1 pixel on a length and/or width; you don't get that if you
    use integer methods but of course it's a bit more work to code it.

    >
    >Prakash
    >--
    >94.5% of all statistics are made up.


    very funny :)

    seeyafrom
    l

    --
    echo |sed 's/\(.\)\(.\)/\2\1/g'
    laura fairhead, Sep 23, 2003
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steven

    while loop in a while loop

    Steven, Mar 24, 2005, in forum: Java
    Replies:
    5
    Views:
    2,218
    Tim Slattery
    Mar 30, 2005
  2. Daniel Pitts
    Replies:
    14
    Views:
    1,217
    Patricia Shanahan
    Dec 23, 2006
  3. Uday Bidkar
    Replies:
    4
    Views:
    476
    =?ISO-8859-15?Q?Juli=E1n?= Albo
    Dec 12, 2006
  4. Roedy Green
    Replies:
    3
    Views:
    415
    Mike Schilling
    Sep 13, 2008
  5. Isaac Won
    Replies:
    9
    Views:
    354
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page