TCL - Select nth term in a list of floating values - tcl

Does anyone know of a way to select a specific value in a list that consists of floating values (i.e. an equivalent method to Lindex used for integers in a list)?

Tcl's lindex command can work on any arbitrary list, but the indices themselves have to be either integers or end-relative (e.g., end-1). The values in the list can most definitely be floating point numbers (or any other value, including strings and lists and variable names and snippets of code and database handles and …).
set theList [list 1.23 2.34 3.45 [expr {4.56 + 5.67}]]
puts [lindex $theList 3]
The indices have to be integers because they are logically counting positions from the start of the list (or from the end of the list for end-relative, of course). It makes no sense at all to count positions using floating point numbers.
If you're trying to find where a floating point number would belong in a sortd list of floating point numbers, the lsearch command is the right tool (with the options below).
set idx [lsearch -sorted -real -bisect $theList 6.78]
# Now $idx is the index where the value is *or* the index before where it would be inserted
# In particular, $idx+1 indicates the first element later than the value
The options above are:
-sorted — Tells the lsearch command that the list is sorted (so it can use a binary search algorithm instead of a linear one)
-real — Tells the lsearch command that it is using floating point comparisons
-bisect — Tells the lsearch command to find the slot for the value (and not return -1 if it isn't already in there)

Related

How to add a huge list of elements in a tcl list?

I have used some tcl code in a design tool to get the list of standard cells in a single list.
Tcl has a limitation of processing a large number of elements to read from any list. How do I split these list of standard cells in a single data structure for the tool to read?
If you've got a big list that you've got to split into small chunks for processing and don't want to just do all the pieces one by one with foreach, you can do this:
set big_list {lots and lots and lots...}
set index 0
set stride 10
while true {
set chunk [lrange $big_list $index [expr {$index + $stride - 1}]]
# Nothing left; got to the end
if {![llength $chunk]} break
incr index $stride
process_chunk $chunk
}
Tune the stride size for how much you can feed through. (Theoretically, you can do auto-tuning of the stride length if there's some complex limit involved. Practically, just pick something by hand that works and isn't too inefficient; auto-tuning algorithms are always quite a lot more complicated.)

What's the best way to join two lists?

I have two lists that contain some data (numeric data or/and strings)?
How do I join these two lists, assuming that the lists do not contain sublists?
Which choice is preferred and why?
set first [concat $first $second]
lappend first $second
append first " $second"
It is fine to use concat and that is even highly efficient in some cases (it is the recommended technique in 8.4 and before, and not too bad in later versions). However, your second option with lappend will not work at all, and the version with append will work, but will also be horribly inefficient.
Other versions that will work:
# Strongly recommended from 8.6.1 on
set first [list {*}$first {*}$second]
lappend first {*}$second
The reason why the first of those is recommended from 8.6.1 onwards is that the compiler is able to optimise it to a direct "list-concatenate" operation.
Examples
% set first {a b c}
a b c
% set second {1 2 3}
1 2 3
% set first [concat $first $second]; # #1 is correct
a b c 1 2 3
% set first {a b c}
a b c
% lappend first $second; # #2 is wrong: appends the whole `second` list to `first
a b c {1 2 3}
Discussion
I looked up the documentation, also experiment with some lists and found out that:
Your first choice, concat is correct
lappend does not work because it treats $second as one element, not a list
append works, but you are treating your lists as string. I don't know what the implications are, but it does not communicate the intention that first and second are lists.
Maybe a bit old, but wanted to clarify;
As already stated, the standard way to merge 2 lists is via concat pre-v8.6. However please note that concat gets very inefficient when dealing with long lists, since it analyzes the lists as part of the merge. eg when merging lists, the larger they get the slower they merge.
Both appends do not merge "lists", they just add to an existing list (lappend) or variable (append). Both appends have no impact to speed, since they do not analyze anything when appending.
If merging single entry list elements, one could merge them via set first [join [lappend first $second]] but only if dealing with simple/single elements within each list (ie no spaces per element).
To add to the other answers, I ran a rough benchmark comparing the different versions (tclsh 8.6.13).
#! /usr/bin/env tclsh
set a {1}
for {set i 0} {$i < 25} {incr i} {
switch $argv {
list {
set a [list {*}$a {*}$a]
}
concat {
set a [concat $a $a]
}
lappend {
lappend a {*}$a
}
append {
append a " $a"
}
}
}
Results:
./test.tcl lappend 0.28s user 0.51s system 99% cpu 0.795 total
./test.tcl list 0.22s user 0.29s system 99% cpu 0.511 total
./test.tcl append 0.04s user 0.08s system 99% cpu 0.115 total
./test.tcl concat 0.04s user 0.08s system 99% cpu 0.112 total
Note that the semantics aren't quite the same between the different versions. For example, list will re-quote list elements.

round number to 2 decimal places

I need to round a number to two decimal places.
Right now the following rounds to the nearest integer I guess
puts [expr {round($total_rate)}]
If I do something like below it does not work. Is there another way around?
puts [expr {round($total_rate,2)}]
The simplest way to round to a specific number of decimal places is with format:
puts [format "%.2f" $total_rate]
Be aware that if you're using the rounded value for further calculations instead of display to users, most values that you print using rounding to X decimal places will not have an exact representation in binary arithmetic (which Tcl uses internally, like vast numbers of other programming languages). It's best to reserve rounding to a specific number of DPs to the point where you're showing values to people.
expr {double(round(100*$total_rate))/100}
example
% set total_rate 1.5678
1.5678
% expr {double(round(100*$total_rate))/100}
1.57
% set total_rate 1.4321
1.4321
% expr {double(round(100*$total_rate))/100}
1.43
puts [format "%.2f" $total_rate]
By using format, we can see the result in output but how to use the same value in the program, i.e., we can see 1.448 as 1.45 in the output but can we use 1.45 in the program then.
It is unclear whether the original question "I need to round a number" really was "I need to print out a rounded-off value of a number". The latter is really best answered with a [format ...], but the former could be interpreted as a need for a number of significant digits, i.e. how to adjust the number itself, and not just to format the printout string. I think the only answer that serves this purpose so far is the elegant one Donal Fellows has provided. However, for "significant digits" instead of "digits after the decimal" I think a small modification is in order: get the number to be between 1 and 10 first (or between 0.1 and 1, if that is your convention), then trim the number of digits after the decimal. Without that, something like roundto(0.00000001234567,4) will get you a zero.
proc tcl::mathfunc::roundto {value sigfigs} {
set pow [expr ($sigfigs-1)-floor(log10($value))]
expr {round(10**$pow*$value)/10.0**$pow}
}
expr roundto(0.000000123456789,5)
produces a value rounded off to 5 significant figures:
1.2346e-7

Generate a powerset with the help of a binary representation

I know that "a powerset is simply any number between 0 and 2^N-1 where N is number of set members and one in binary presentation denotes presence of corresponding member".
(Hynek -Pichi- Vychodil)
I would like to generate a powerset using this mapping from the binary representation to the actual set elements.
How can I do this with Erlang?
I have tried to modify this, but with no success.
UPD: My goal is to write an iterative algorithm that generates a powerset of a set without keeping a stack. I tend to think that binary representation could help me with that.
Here is the successful solution in Ruby, but I need to write it in Erlang.
UPD2: Here is the solution in pseudocode, I would like to make something similar in Erlang.
First of all, I would note that with Erlang a recursive solution does not necessarily imply it will consume extra stack. When a method is tail-recursive (i.e., the last thing it does is the recursive call), the compiler will re-write it into modifying the parameters followed by a jump to the beginning of the method. This is fairly standard for functional languages.
To generate a list of all the numbers A to B, use the library method lists:seq(A, B).
To translate a list of values (such as the list from 0 to 2^N-1) into another list of values (such as the set generated from its binary representation), use lists:map or a list comprehension.
Instead of splitting a number into its binary representation, you might want to consider turning that around and checking whether the corresponding bit is set in each M value (in 0 to 2^N-1) by generating a list of power-of-2-bitmasks. Then, you can do a binary AND to see if the bit is set.
Putting all of that together, you get a solution such as:
generate_powerset(List) ->
% Do some pre-processing of the list to help with checks later.
% This involves modifying the list to combine the element with
% the bitmask it will need later on, such as:
% [a, b, c, d, e] ==> [{1,a}, {2,b}, {4,c}, {8,d}, {16,e}]
PowersOf2 = [1 bsl (X-1) || X <- lists:seq(1, length(List))],
ListWithMasks = lists:zip(PowersOf2, List),
% Generate the list from 0 to 1^N - 1
AllMs = lists:seq(0, (1 bsl length(List)) - 1),
% For each value, generate the corresponding subset
lists:map(fun (M) -> generate_subset(M, ListWithMasks) end, AllMs).
% or, using a list comprehension:
% [generate_subset(M, ListWithMasks) || M <- AllMs].
generate_subset(M, ListWithMasks) ->
% List comprehension: choose each element where the Mask value has
% the corresponding bit set in M.
[Element || {Mask, Element} <- ListWithMasks, M band Mask =/= 0].
However, you can also achieve the same thing using tail recursion without consuming stack space. It also doesn't need to generate or keep around the list from 0 to 2^N-1.
generate_powerset(List) ->
% same preliminary steps as above...
PowersOf2 = [1 bsl (X-1) || X <- lists:seq(1, length(List))],
ListWithMasks = lists:zip(PowersOf2, List),
% call tail-recursive helper method -- it can have the same name
% as long as it has different arity.
generate_powerset(ListWithMasks, (1 bsl length(List)) - 1, []).
generate_powerset(_ListWithMasks, -1, Acc) -> Acc;
generate_powerset(ListWithMasks, M, Acc) ->
generate_powerset(ListWithMasks, M-1,
[generate_subset(M, ListWithMasks) | Acc]).
% same as above...
generate_subset(M, ListWithMasks) ->
[Element || {Mask, Element} <- ListWithMasks, M band Mask =/= 0].
Note that when generating the list of subsets, you'll want to put new elements at the head of the list. Lists are singly-linked and immutable, so if you want to put an element anywhere but the beginning, it has to update the "next" pointers, which causes the list to be copied. That's why the helper function puts the Acc list at the tail instead of doing Acc ++ [generate_subset(...)]. In this case, since we're counting down instead of up, we're already going backwards, so it ends up coming out in the same order.
So, in conclusion,
Looping in Erlang is idiomatically done via a tail recursive function or using a variation of lists:map.
In many (most?) functional languages, including Erlang, tail recursion does not consume extra stack space since it is implemented using jumps.
List construction is typically done backwards (i.e., [NewElement | ExistingList]) for efficiency reasons.
You generally don't want to find the Nth item in a list (using lists:nth) since lists are singly-linked: it would have to iterate the list over and over again. Instead, find a way to iterate the list once, such as how I pre-processed the bit masks above.

Count non-symmetric bytes

I am looking for a clean way to list the (8 bit) integers whose binary representation is not the same as another integer up to rotation and reflection.
For example the list will probably start as
0
1
(2=10b is skipped because you can rotate the bits in 1, therefore all powers of 2 are skipped. Also every number except 0 will be odd)
3=11b
5=101b
7=111b
9=1001b
11=1011b (so 13=1101b will be skipped because 11010000b is a reflection of 1101b which can then be rotated to the right 4 times )
.
.
.
Also ideally how could this be generalized to numbers with different numbers of bits, (16, 32, or just n) and other bases beside 2.
Since #John Smith thought my comment was a good answer, here it is an answer.
The answers here may be illuminating.
Thanks to Jeffromi for explaining the problem better -- I've deleted my previous answer.
Here's another solution in Perl. Perl is a good language for this sort of problem because it makes it easy to treat numbers as text and text as numbers.
i: for $i (0..255) {
$n1 = sprintf "%08b", $i; # binary representation of $i
$n2 = $n1; # "unreflected" copy of $n1
$n3 = reverse $n1; # "reflection" of $n1
for $j (1..8) {
$n2 = chop($n2) . $n2; # "rotate" $n2
$n3 = chop($n3) . $n3; # "rotate" $n3
next i if $found{$n2} or $found{$n3};
}
# if we get here, we rotated $n2 and $n3 8 times
# and didn't get a nonsymmetric byte that we've
# seen before -- this is a nonsymmetric byte
$found{$n1}++;
print "$i $n1\n";
}
This isn't as simple as the previous solution, but the jist is to try out all 16 combinations (2 reflections x 8 rotations) and compare them with all of the nonsymmetric bytes you've seen before.
There's a operator for bit shifting with rotation in Perl, but the chop($num) . $num idiom I used generalizes better to problems with base n.
You can use a sieve, similar to the sieve of Eratosthenes for prime numbers.
Use a bit array (BitSet in Java) with one bit for each number.
Initially mark all bits.
Go sequentially through the bit array until you find the next bit that is set at index n, this is a number in your set. Then clear the bits of all other numbers that can be reached from n via rotation and mirroring.
On today's machines this is feasible up to 32 bits, which would use 512MB of memory.
An alternative solution to Eratosthenes' Sieve would be to construct a test T(k) that returns True or False for any given k.
It would be slower, but this way no storage would be needed, so it would extend more readily to arbitrary data length.
If you simplify the problem for a moment, and say we are simply looking to discard reflections, then it would be easy:
T_ref(k) returns true iff k <= Reflection(k).
As for rotating bits, exactly the same can be done:
T_rot(k) returns true iff k == MIN{the set of all rotations of k}
You can think of dividing your integers up into a bunch of equivalence classes E(k) where E(k) is the set of all reflection&rotation permutations of k.
You might want to take a moment to satisfy yourself that the set of natural numbers N partitions itself readily into such disjoint subsets.
Then the set
{k s.t. k == MIN(E(k)) }
will guarantee to contain exactly one element from each equivalence class.
This would make a really nice interview question.