perlboy_emeritus has asked for the wisdom of the Perl Monks concerning the following question:
Greetings Monks,
I ported the Perl/Tk example below of factorial from Tcl/Tk, not because it is particularly interesting, but because I am working on a cryptology/encryption application, and I want to understand the Tk widget basics before tackling the more ambitious project. I'll state the problem up front, as if I simply post the code without explanation, we all might get lost in the weeds of the debugging statements I inserted to validate my issue.
Stated as succinctly as possible, I enter an integer in an Entry widget and I calculate the factorial of that number and display it in a Label widget. I bind the Entry widget to <Return> and also configure a Calc button to also call the factorial function. Unfortunately, the Label display integer overflows at any number > 2**31 -1, which means Tk's default int in that widget is a 32 bit int. In "Tcl and the Tk Toolkit" the author's call out the existence of the Tk functions wide() and entier() as means to expand the size of int used internally, but I have not been able to get either to work. There are 5 different functions that exercise calculations that can display overflow; an interesting one is exponentiation(), which switches to floating point math when the result exceeds 2**31 -1. Label displays this number correctly, but as a float, not an integer. The text suggests that Tk converts back and forth between int and float math as needed under the covers, but that does not seem to work for my two factorial() functions, one of which is recursive.
To exercise the different functions you must match a bind expression with a -command expression in the Calc button. Just uncomment the two you wish to try. Debugging statements will be written to the console. Factorial() calculations overflow at 13! while intOverFlow() overflows at 2**31.
What I hope the Monks brotherhood/sisterhood can explain is how to get Tk/Tkx to use 64 bit ints, or with entier(), ints of unlimited length?
Here be the code
#!/usr/bin/env -S perl ##!/usr/bin/env -S perl -wd use warnings; use strict; use feature ":all"; use Tkx; use Tk; sub factorial { my ($n) = @_; return 1 if $n == 0; return factorial($n-1) * $n; } sub recurWrapper { my $n = factorial(@_); say "after recursion: ", $n; return $n; } sub factorial_1 { (my $val) = @_; my $result = 1; while ( $val > 0 ) { $result *= $val; $val--; } say "\$result inside factorial_1: $result"; return $result; } sub intOverflow { (my $val) = @_; return $val *= 1; } sub exponential { (my $val) = @_; my $n = 2**$val; say "\$result inside exponential $n"; return $n; } say 'factorial(17): ', factorial(17); say 'factorial_1(17): ', factorial_1(17); say ''; say 'exponential(31): ', exponential(31); say 'exponential(32): ', exponential(32); say 'exponential(33): ', exponential(33); say ''; say 'intOverflow(2147483647): ', intOverflow(2147483647); say 'intOverflow(2147483648): ', intOverflow(2147483648); say 'intOverflow(2147483649): ', intOverflow(2147483649); my $mw = Tkx::widget->new("."); $mw->g_wm_title("Factorial Calculator"); $mw->g_wm_minsize(200, 150); my $result; my $value; my $v = $mw->new_entry( -width => 6, -relief => "sunken", -textvariable => \$value, ); #$v->Tkx::bind('<Return>', sub { say $value; $result = factorial($valu +e); say $result; } ); $v->Tkx::bind('<Return>', sub { say $value; $result = recurWrapper($va +lue); say $result; } ); #$v->Tkx::bind('<Return>', sub { say $value; $result = factorial_1($va +lue); say $result; } ); #$v->Tkx::bind('<Return>', sub { say $value; $result = exponential($va +lue); say $result; } ); #$v->Tkx::bind('<Return>', sub { say $value; $result = intOverFlow($va +lue); say $result; } ); my $desc = $mw->new_label( -text => "Factorial is:", ); my $r = $mw->new_label( -textvariable => \$result, ); my $calc = $mw->new_button( -text => "Calculate", # -command => sub { say $value; $result = factorial($value); say $ +result; }, -command => sub { say $value; $result = recurWrapper($value); sa +y $result; }, # -command => sub { say $value; $result = factorial_1($value); say $ +result; }, # -command => sub { say $value; $result = exponential($value); say $ +result; }, # -command => sub { say $value; $result = intOverflow($value); say $ +result; }, ); my $q = $mw->new_button( -text => "QUIT", -command => sub { $mw->g_destroy; }, ); Tkx::grid($v, $desc, $r, -padx => 10, -pady => 10); Tkx::grid($calc, "-", "-", -padx => 10, -pady => 5); Tkx::grid($q, "-", "-", -padx => 10, -pady => 5); Tkx::MainLoop() __END__
Thanks in advance for any insights.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Perl/Tk int overflow in Label widget
by choroba (Cardinal) on Nov 06, 2023 at 21:19 UTC | |
by perlboy_emeritus (Scribe) on Nov 06, 2023 at 22:36 UTC | |
by perlboy_emeritus (Scribe) on Nov 07, 2023 at 22:50 UTC | |
by choroba (Cardinal) on Nov 07, 2023 at 22:59 UTC | |
by perlboy_emeritus (Scribe) on Nov 06, 2023 at 22:46 UTC |