Please help me with the simple tcl code - linux

It is a simple code which gives the output when a number is raised to another number.But it is always returning the square of the number and not looping.
Please help guys
#!/usr/bin/tclsh
proc raise {{base} {pow} args} {
for {set base1 $base} {$pow >= 0} {incr $pow -1} {
set ans [expr $base * $base1 ]
set base $ans
return $ans
}
}

You are allowing the loop to go through at most 1 iteration. This is because return quits the current proc (the loop as well automatically).
Fixing that part would give:
#!/usr/bin/tclsh
proc raise {{base} {pow} args} {
for {set base1 $base} {$pow >= 0} {incr $pow -1} {
set ans [expr $base * $base1 ]
set base $ans
}
return $ans
}
But.. that doesn't quite give you the answer, does it. The logic of your code is not quite correct. I think it should be:
proc raise {base pow} {
for {set base1 $base} {$pow > 1} {incr pow -1} {
set ans [expr {$base * $base1}]
set base $ans
}
return $ans
}
incr takes a variable name, not a variable, and you want to iterate until the power is above 1. If it is 1, then you get the base, hence you don't loop. The last change was to brace the expressions. To make the above work for powers of 0 as well, you can use Peter's proc.
But all that said, why don't you use the inbuilt operator for this?
set ans [expr {$base**$pow}]
or even:
set ans [expr {pow($base,$pow)}]

A slightly less messy solution which gives a correct answer for $pow = 0 too:
proc raise {base pow} {
for {set answer 1} {$pow > 0} {incr pow -1} {
set answer [expr {$answer * $base}]
}
return $answer
}
It's often useful, when experimenting with code, to be stingy with variables and command invocations: when you're sure that you can't eliminate any more of them, you probably have fairly efficient, readable, and robust code.
Documentation: expr, for, incr, proc, return, set

just a first-glance-answer: don't you return too early?
#!/usr/bin/tclsh
proc raise {{base} {pow} args} {
for {set base1 $base} {$pow >= 0} {incr $pow -1} {
set ans [expr $base * $base1 ]
set base $ans
}
return $ans
}

Related

Proper ways to use threads in TCL

So I have the following code -
#!/usr/bin/env tclsh
package require Thread
thread::create {
for {set i 0} {$i < 1000} {incr i} {
puts "hello T1 $i"
}
thread::wait
}
thread::create {
for {set j 0} {$j < 1000} {incr j} {
puts "hello T2 $j"
}
thread::wait
}
It runs, but the first thread run more iterations than the loop count (1000) and the second thread has far fewer iterations than its loop count (1000 ). Can someone point out what's wrong with this code? Many thanks for your help.

Perl - parse string to integer from arguments and compare it

There are two arguments: $a and $b, and both are strings. They are will be compared, if a is greater/less/equal to b.
Other people can achieve 42 char, I don't know how to achieve it.
AUTOLOAD {
$_[0] + 0 > $_[1] + 0 ? "greater" :
$_[1] == $_[0] ? "equal" : "less"
}
This will do as you ask, but you give almost no information on your program so it is very difficult to suggest anything
use strict;
use warnings 'all';
for ( [ 1, 2 ], [2, 2], [3, 2] ) {
my ($aa, $bb) = #$_;
printf "%d is %s %d\n", $aa, compare($aa, $bb), $bb;
}
sub compare {
my ($aa, $bb) = #_;
('less than', 'equal to', 'greater than')[($aa <=> $bb) + 1];
}
output
1 is less than 2
2 is equal to 2
3 is greater than 2

Tcl: strange behavior of string list

In my following code, I generate a string list in a for loop like this:
set section 5;
set value 2;
set value_range_new "";
for { set i [expr -$section-1]} {$i <= $section} {incr i} {
if {$i < [expr -$section]} {
lappend value_range_new "\<[expr [expr $i+1]*$value]";
} elseif {$i == $section} {
lappend value_range_new "\>[expr $i*$value]";
} else {
lappend value_range_new "\[[expr $i*$value]\,[expr [expr $i +1]*$value]\)";
}
}
then if I puts the list out, the result is following:
<-10 {[-10,-8)} {[-8,-6)} {[-6,-4)} {[-4,-2)} {[-2,0)} {[0,2)} {[2,4)} {[4,6)} {[6,8)} {[8,10)} >10
The confusing point is I do not understand where the {} comes from. If I define the list manually like following :
set a "\<-8 \[-8,-6\) \[-6,-4\) ";
the puts result has no {}. So what's wrong with my code, and how to remove/
In Tcl, you need to be aware which commands want to work with lists and which commands want to work with strings. lappend is a list command. puts takes a string. When you give puts a list, Tcl will convert the list into its string representation. That means that you'll see some extra braces and perhaps backslashes to protect list elements that have special characters (like [ and ]).
You can convert the list into a string easily with the join command.
For building strings, the format command can aid readability.
Additionally, you don't need to next expr commands, use parentheses; and brace your expressions:
set section 5;
set value 2;
set value_range_new "";
for { set i [expr {-$section-1}]} {$i <= $section} {incr i} {
set this [expr {$i * $value}]
set next [expr {($i + 1) * $value}]
if {$i < -$section} {
lappend value_range_new [format {<%d} $next]
} elseif {$i == $section} {
lappend value_range_new [format {>%d} $this]
} else {
lappend value_range_new [format {[%d,%d)} $this $next]
}
}
puts [join $value_range_new]
outputs
<-10 [-10,-8) [-8,-6) [-6,-4) [-4,-2) [-2,0) [0,2) [2,4) [4,6) [6,8) [8,10) >10
The shorter variant of algorithm. Not a single if is needed actually.
set section 5;
set value 2;
set this [expr {-$section * $value}]
set value_range_new [format {<%d} $this]
for {set i -$section} {$i < $section} {incr i} {
lappend value_range_new [format {[%d,%d)} $this [incr this $value]]
}
lappend value_range_new [format {>%d} $this]
puts [join $value_range_new]

How can I compare 2 variables if I don't know what they are?

If I have 2 variables $x and $y somewhere in the code flow and I don't really know if they contain numbers or string, how do I compare them?
I mean for strings we use eq etc while for numbers == or <= etc
Also what about greater/less etc?
If you don't know what they are, how can you ask if they're the same?
Specifically, do you consider these two to be the same?
"1"
"1.0"
Numerically, they both represent one, but stringily they contain different characters, so are different.
greater/less for strings can be done with cmp.
if ( ( $a cmp $b ) == 0 ) { print "a == b\n" }
elsif ( ( $a cmp $b ) < 0 ) { print "a < b\n" }
elsif ( ( $a cmp $b ) > 0 ) { print "a > b\n" }
To reiterate a comment above "123" cmp "56" will give less than.
So you may want to do something like this:
if ( compareEm($a, $b) == 0 ) { print "a == b\n" }
elsif ( compareEm($a, $b) < 0 ) { print "a < b\n" }
elsif ( compareEm($a, $b) > 0 ) { print "a > b\n" }
sub compareEm {
my ( $a, $b ) = #_;
my $isnum = qr/(?=.)(?!^\.$)^[\-\+]?\d*\.?\d*$/o;
return ( $a =~ $isnum && $b =~ $isnum ) ? $a <=> $b : $a cmp $b;
}
Use eq, it will always work...
If you don't know whether your data is strings or numbers then it's usually perfectly safe to treat them as strings. If you want to treat your data as numbers, then you should probably validate the input to ensure that it is in the correct format.

What's the mistake in my recursive subroutine?

This subroutine generates string combinations of the letters using the letters from A to the Mth letter of the Alphabet with length N.
sub genString
{
my($m,$n,$str,$letter,$temp,$i) = #_;
if($n == 0){
$letter = chr(ord("A")+($i+=1));
if($temp == 1){ print "$str\n"; }
else{
for($j = 0 ; $j < temp-1 ; $j++){
if(ord(substr($str,$j,1)) < ord(substr($str,$j+1,1))){$do_print = 1;}
else{
$do_print = 0;
break;
}
}
if($do_print == 1){ print "$str\n"; }
}
}
else{
for($j = ord($letter) ; $j < ord($letter)+$m ; $j++){
genString($m,$n-1,$str.chr($j),$letter,$temp,$i);
}
}
}
&genString($m,$n,$str,"A",$n,0);
Example:
Input: M=4; N=3;
Output: ABC ABD ACD BCD
I tried similar to this in Ruby and it works, but in Perl, it's an infinite loop, and I don't know why. I'm new here in Perl. What should I do? (Sorry if my code is kinda lengthy)
Please always use use strict; and use warnings; in your code, especially when posting code and asking for help. Also always declare local variables with my.
In this case even without having tried it I'm pretty sure something like $j referring to a global variable is causing you a lot of headache -- something use strict would have caught.
By default, variables are globals in perl (though undeclared and unqualified use of them will be prevented by use strict). For your recursion to work, you'll need to make some of them lexical, for instance, changing:
for($j = 0 ; $j < temp-1 ; $j++){
to
for (my $j = 0; $j < $temp-1; $j++) {
or better yet, just
for my $j (0..$temp-2) {
Your code is very hard to read. I can't understand the algorithm, and I don't see the purpose of so many parameters to the subroutine, especially $temp which doesn't appear to change, and you don't say what its initial value is set to in the outermost call.
This code appears to do what you want, with a similar algorithm
use strict;
use warnings;
genString(4, 3);
sub genString {
my ($m, $n, $str, $i) = #_;
if ($n == 0) {
print $str, "\n";
}
else {
for my $off ($i // 0 .. $m - $n) {
$str //= '';
genString($m, $n-1, $str.chr(ord('A') + $off), $off+1);
}
}
}
output
ABC
ABD
ACD
BCD

Resources