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

I'm running Perl 5.20.1 on openSUSE 13.2. The application involves scaling dimensions for a model railroad. So 12 by 14 inches should scale to 270 by 315 inches with a scale factor of 22.5 (G scale)

The calc subroutine shows 264 by 308, which is a scale of 22.0. The printed trace shows the correct x,y and scale values with the calculated values. When you change one of the inputs and hit enter, the fractional part is sometimes ignored. It may be correct for one of the calculations and not the other.

It's a puzzlement!

#!/usr/bin/perl -w use strict; use Tk; my $x = '12.0'; my $y = '14.0'; my $scale = '22.5'; my $xmax = $x * $scale; my $ymax = $y * $scale; my $shouldBe = sprintf("Originally X=%4.1f, Y=%4.1f, scale=%4.1f X-max +=%8.4f, Y-Max=%8.4f",$x,$y,$scale,$xmax,$ymax); my $results; my $mw = MainWindow->new; my $InFrame = $mw->Frame()->pack(-side=>'top'); $InFrame->Label(-text=>"X= ")->pack(-side=>'left'); $InFrame->Entry(-textvariable=>\$x)->pack(-side=>'left'); $InFrame->Label(-text=>" Y= ")->pack(-side=>'left'); $InFrame->Entry(-textvariable=>\$y)->pack(-side=>'left'); $InFrame->Label(-text=>"Scale= ")->pack(-side=>'left'); $InFrame->Entry(-textvariable=>\$scale)->pack(-side=>'left'); my $OutFrame = $mw->Frame()->pack(-side=>'top'); $OutFrame->Label(-textvariable=>\$results)->pack(-side=>'top'); $OutFrame->Label(-textvariable=>\$shouldBe)->pack(-side=>'top'); $mw->bind("<Key-KP_Enter>",\&calc); $mw->bind("<Key-Return>",\&calc); calc(); MainLoop; sub calc { $xmax = $x * $scale; $ymax = $y * $scale; $results = sprintf("Calculated X-max=%8.4f, Y-Max=%8.4f",$xmax,$ymax +); print "$x, $y, $scale, $xmax, $ymax\n"; }

Can anyone explain this?

Replies are listed 'Best First'.
Re: Perl is ignoring fractional part sometimes
by Anonymous Monk on Jul 17, 2016 at 23:54 UTC

    With this change it works on my system (perl 5.24.0)

    I'd guess it's something in the number/string duality in fetching values with -textvariable

    sub calc { my $t = $scale; $xmax = $x * $t; $ymax = $y * $t; $results = sprintf("Calculated X-max=%8.4f, Y-Max=%8.4f",$xmax,$ymax +); print "$x, $y, $scale, $xmax, $ymax\n"; }

      It doesn't change anything on perl 5.20.1. I tried:

      sub calc { my $t = $scale; $xmax = $x * $t; $ymax = $y * $t; $results = sprintf("Calculated X-max=%8.4f, Y-Max=%8.4f",$xmax,$ymax +); print " $x , $y , $scale , $t , $xmax , $ymax\n"; print "'$x','$y','$scale','$t','$xmax','$ymax'\n"; print join(', ',hexify($x),hexify($y),hexify($scale),hexify($t),hexi +fy($xmax),hexify($ymax))."\n\n"; } sub hexify { my $s = shift; $s =~ s/(.)/sprintf("%x ",ord($1))/eg; return $s; }

      The values all print out the same with the incorrect products. No extra characters whether I print $x or '$x' or the hexified version

      However, if I change the second line to: my $t = $scale.' '; it works!

      I can't really call it solved, since I don't know why it's doing this. But at least, I have a work-around to make my main program behave.

Re: Perl is ignoring fractional part sometimes
by haukex (Archbishop) on Jul 18, 2016 at 09:58 UTC

    Hi jinnicky,

    Although I'm no Tk expert, I investigated the AM's hint about dual-valued variables, and there indeed seems to be something buggy going on. I boiled the code down to the following:

    use warnings; use strict; use Tk; use Devel::Peek; my $scale = '22.5 '; # note the space in the output as well my $foo = 0 + $scale; # use in numeric context (set NV and IV) Dump($scale); my $mw = MainWindow->new; $mw->Entry(-textvariable=>\$scale)->pack; $mw->bind("<Key-Return>",\&calc); calc(); MainLoop; sub calc { print "str: <$scale> / num: <".(0+$scale)."> \n"; }

    Output:

    SV = PVNV(0x1e3f350) at 0x1e59a40 REFCNT = 2 FLAGS = (NOK,POK,IsCOW,pIOK,pNOK,pPOK) IV = 22 NV = 22.5 PV = 0x1e6f870 "22.5 "\0 CUR = 5 LEN = 10 COW_REFCNT = 1 str: <22.5 > / num: <22>

    It appears that binding $scale to the Tk::Entry widget is causing the variable to become dual-valued with the wrong initial values (I guess the PV and IV values?). This only seems to be happening once on init though, when I input something everything seems to work fine. I don't know enough about the internals of Tk to really suggest a solution (perhaps a bug report is in order), but some workaround(s). You apparently can initialize $scale with a numeric value to begin with, my $scale = 22.5; seems to work for me. Or, as you've already discovered, you can stringify $scale when reading it out.

    Hope this helps,
    -- Hauke D

      It looks like I'm going to have to stringify every value I get from a Tk::Entry box.

      OpenSUSE Leap 42.1 regressed perl to 5.18.2 from 5.20.1 in 13.2. It didn't work either. I'm currently upgrading Manjaro which has an up to date perl 5.24.0. I'll report on that once the update is done.

      Looks like I'm going to have to submit a bug on Tk. Strange that no one has noticed this already.

      Thanks for all your help

        Just for completeness, I tested it with python and tcl to see if the underlying Tk has a problem. Both worked without problem.

        I did test it on perl 5.24.0 with the following code:

        #!/usr/bin/perl -w use warnings; use strict; use Tk; use Devel::Peek; my $scale = 22.5; my $x = 14; my $foo = $x * $scale; # use in numeric context (set NV and IV) my $sb = 22.5 * 14; my $i=0; print "\n0 str: <$scale> / num: <".(0+$scale)."> product $foo should b +e $sb\n"; Dump($scale); my $mw = MainWindow->new; $mw->Entry(-textvariable=>\$scale)->pack; $mw->bind("<Key-Return>",\&calc); MainLoop; sub calc { $foo = $scale * $x; my $s2 = $scale.' '; my $foobar = $s2 * $x; $i++; print "\n$i str: <$scale> / num: <".(0+$scale)."> product $foo str +ingified $foobar should be $sb\n"; Dump($scale); }

        This seemed to work originally. If you just hit enter a couple of times it fails with:

        0 str: <22.5> / num: <22.5> product 315 should be 315 SV = PVNV(0x19572d0) at 0x1982d20 REFCNT = 2 FLAGS = (NOK,pIOK,pNOK) IV = 22 NV = 22.5 PV = 0x196fa80 "22.5"\0 CUR = 4 LEN = 32 1 str: <22.5> / num: <22> product 315 stringified 315 should be 315 SV = PVMG(0x1ed5f60) at 0x1982d20 REFCNT = 3 FLAGS = (GMG,SMG,IOK,NOK,POK,pIOK,pNOK,pPOK,UTF8) IV = 22 NV = 22.5 PV = 0x196fa80 "22.5"\0 [UTF8 "22.5"] CUR = 4 LEN = 32 MAGIC = 0x1fa6a30 MG_VIRTUAL = &PL_vtbl_uvar MG_TYPE = PERL_MAGIC_uvar(U) MG_LEN = 24 MG_PTR = 0x1f24b40 "\260(=\252\254\177\0\0\20==\252\254\177\0\0\0j +\372\1\0\0\0\0" 2 str: <22.5> / num: <22> product 308 stringified 315 should be 315 SV = PVMG(0x1ed5f60) at 0x1982d20 REFCNT = 3 FLAGS = (GMG,SMG,IOK,NOK,POK,pIOK,pNOK,pPOK,UTF8) IV = 22 NV = 22.5 PV = 0x196fa80 "22.5"\0 [UTF8 "22.5"] CUR = 4 LEN = 32 MAGIC = 0x1fa6a30 MG_VIRTUAL = &PL_vtbl_uvar MG_TYPE = PERL_MAGIC_uvar(U) MG_LEN = 24 MG_PTR = 0x1f24b40 "\260(=\252\254\177\0\0\20==\252\254\177\0\0\0j +\372\1\0\0\0\0"

        As you can see in section 2, the product reverted to 308 going back to the IV value. The same thing happened on 5.20.1. The flags changed a little, but the results were the same.

        I've submitted a report on this to bug-Tk at rt.cpan.org

Re: Perl is ignoring fractional part sometimes
by Anonymous Monk on Jul 17, 2016 at 22:52 UTC

    hi, remove all tk stuff from your program, and just give calc() various inputs and watch what output you get

      As expected, this works

      #!/usr/bin/perl -w use strict; my $x = 12; my $y = 14; my $scale = '22.5'; my ($xmax,$ymax,$input); calc(); while(1) { print "Enter X,Y,Scale: "; $input = <>; chomp $input; last if $input =~ m/^\s*$/; ($x,$y,$scale) = split(/\s*,\s*/,$input); calc(); } sub calc { $xmax = $x * $scale; $ymax = $y * $scale; print "$x, $y, $scale, $xmax, $ymax\n"; }

      So it's something that Tk is doing to cause the problem