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

Hello,

Consider the following code:

start=1.6; for($inc=.1;$inc<=.9;$inc=$inc+.1{ #print"\nThe value of inc:"; #print"\n$inc"; $start_pt=$start+$inc; #print"\nThe value of start_pt :"; #print"\n$start_pt"; + SWITCH: {if ($start_pt==2) {$start_pt=$start_pt-.9; last SWITCH;} if($start_pt==2.1){$start_pt=$start_pt-.99; last SWITCH;} if($start_pt==2.2){$start_pt=$start_pt-1.08;last SWITCH;} if($start_pt==2.3){$start_pt=$start_pt-1.17;last SWITCH;} if($start_pt==2.4){$start_pt=$start_pt-1.26;last SWITCH;} if($start_pt==2.5){$start_pt=$start_pt-1.35;last SWITCH;} $nothing = 1; } #print"\nThe value of start_pt :"; #print"\n$start_pt"; SWITCH: {if ($start_pt==1.7) {$end_pt=1.8; last SWITCH;} if($start_pt==1.8) {$end_pt=1.9; last SWITCH;} if($start_pt==1.9) {$end_pt=1.10; last SWITCH;} if($start_pt==1.10){$end_pt=1.11; last SWITCH;} if($start_pt==1.11){$end_pt=1.12; last SWITCH;} if($start_pt==1.12){$end_pt=1.13; last SWITCH;} if($start_pt==1.13){$end_pt=1.14; last SWITCH;} if($start_pt==1.14){$end_pt=1.15; last SWITCH;} $nothing = 1; } print"\nThe value of end_pt :"; print"\n$end_pt"; }


The first time the value of $start_pt is printed we get
th foll.values:

1.7 1.8 1.9 2 2.1 2.2 2.3 2.4 2.5

When we print the value of $start_pt after the first switch
statement we get:

1.7 1.8 1.9 1.1 1.11 1.12 1.13 1.14 1.15
For the value 1.1 of $start_pt is it possible to have this
value read as 1.10 and not truncated to 1.1.Actually I
need to use these values as text indices in a Tk text
widget.The 1.10 means the 10th char on the first
line.If this value is read as 1.1, this would mean 1st
char on 1st line, which is not what is required.

Also the values of end_pt are printing as:
1.9 1.9 1.11 1.12 1.13 1.14 1.15 1.15

whereas these are the values that need to be printed:
1.8 1.9 1.10 1.11 1.12 1.13 1.14 1.15

What is the mistake here?
Thanx.

Replies are listed 'Best First'.
Re: Simple loop question
by bart (Canon) on Jul 31, 2003 at 11:47 UTC
    You're doing exact comparisons on floating point numbers. Don't ever do that. Multiply everything by 100 so you have integers everywhere, and try again.

    And your code doesn't even compile, it's full of syntax errors. My thoughts are that you haven't even tried this in Perl, but instead transalted it here from some other programming language, just for the purpose of posting it here.

    Update: My mistake, there wheren't as many errors as I first thought. I tried multiplying all numbers by 100, and it gives a different result now, more like you expected.

    You've clearly been hit by the "floating point numbers are not exact" syndrome.

Re: Simple loop question
by fglock (Vicar) on Jul 31, 2003 at 12:55 UTC

    You are using "real" values, but what you really need is "string" values:

    $x = 1; # integer $y = 6; # integer for( 1 .. 10 ) { $start_pt="$x.$y"; # string print " $start_pt "; $y++; } # 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 1.14 1.15
      Hello,

      thanks a lot for the reply.That seems to be a nice
      and simple solution to the problem.I'll try it out.
      Thanx
      Hi,
      Here's my changed code(part of it).

      foreach $mitem(@missing) { $result=$t->search(-forwards,"**",'end'); #print"\nThe start pos of the pattern:"; #print "\n$result"; #1.4 $start=$result+.2; #print "\n$start"; #1.6 $x=substr($start,0,1);# integer $y = substr($start,2,2);# integer #print $y; $z=$y + 1; #print $z; for( 1 .. 10 ) { $start_pt="$x.$y"; # string #print " $start_pt "; $y++; $end_pt="$x.$z"; # string #print " $end_pt "; $z++; $char_read=$t->get("$start_pt","$end_pt"); #print "\nThe charcter:"; #print "\n$char_read" push @chars,$char_read; #print "\nThe word:"; #print "\n@chars"; } #$x=1; #$y=6; #$l=length(@chars); #$fract=(($y+$l)-1); #$wd_end=$x.$fract; #$t->tagConfigure("wrong",-foreground=>"red"); #$t->tagAdd("wrong","$start","$wd_end"); #print "\n@chars"; }

      I'm using the above code inside a subroutine, which is called when a button is clicked in a Tk text widget.

      This for loop: for( 1 .. 10 ) {

      needs to read the word immediately next to the **
      (the first time this pattern is found by $t->search)
      but here this loop reads two words.The loop should stop
      reading characters once it encounters a whitespace.
      I've tried putting a do loop outside the for loop like this

      do { $white_space=" "; for( 1 .. 10 ) { ..... stuff inside for loop. ..... } } until ($char_read eq $white_space);

      but this code just hangs when executed(Argh!).

      What is the problem here?

      Each time the outer foreach loop is executed,
      the search function should look for the first
      occurence of ** in the widget window.The word next
      to the **'s needs to be read, and it's font color set to
      red, using a tag,and the two **'s in front of the word
      deleted.

      The next time around the foreach loop the next ocurrence
      of ** should be located, the next word extracted ,it's
      colour changed, the **'s deleted, and so on.I hope this
      works(!).

      e.g. **word **nextword

      In the above example I need the for loop to read
      'word' and stop once a whitespace is encountered.
      The 'nextword' should be taken care of the next time
      the foreach loop runs.

      Of course we can read a word like this too instead
      of char by char:

      $char_read=$t->get("$start_pt","$start_pt wordend");

      But I'm working on text that is in another language(font)
      and the 'wordend' modifier does not work in my case, though
      it works fine with text in an English font(I tried it)
      So all the trouble.
      Any help would be appreciated.
      Thanx.

        You wrote:

        $start=$result+.2; $x = substr($start,0,1);# integer $y = substr($start,2,2);# integer

        It would be better to work in string mode all the time. If you had "1.8" you would get "2" instead of "1.10".

        How about:

        ($x, $y) = split '\.' => $result; $y += 2;
      Hi,
      yes that helps.I would have messed up the indices(2
      instead of 1.10 otherwise)

      I still have the prob. of reading the word next to the
      **'s and stopping at a whitespace, though.
      :)
Re: Simple loop question
by antirice (Priest) on Jul 31, 2003 at 14:29 UTC

    Beyond the commments about why the comparisons don't work as expected, I would like to point out that if you were to use if-elsif-else conditionals, you could dump the use of labels and last and make the code a bit shorter as well as more readable. You can check out perlsyn for more information on control structures in perl.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1