How to build a prime generator in Forth? - gforth

My aim was to build a prime number generator in Forth. Not a Sieve of Eratosthenes but two nested loops who are bruteforcing all combinations of number A and number B. In the sourcecode, I have a word for the loop, for testing if a condition is true and also some attempt in doing the nested loop. But after executing the code with gforth a stack-underflow error is shown. Maybe some kind of dup is missing somewhere, but it's also possible that the i and j index in the loops is wrong. The problem is, that if i change something in the code, the stack is different. That means, after putting out the index number of the for loop to the screen, it's no longer possible to get access to this number. Also i find it's difficult to get access to variables, because Forth doesn't seem to have variables at all. So I created a helper variable, but it's unclear how to use it.
I know, the code looks a bit confusing, can anybody help?
variable temp
: numbers
10 0 do i . loop
;
: cond
0 dup
0 = if ." equal 0" endif
;
: plain
10 2 mod .
10 3 mod .
10 4 mod .
10 5 mod .
10 6 mod .
10 7 mod .
10 8 mod .
10 9 mod .
;
: plain2
10 temp !
\ 10 0 do temp # i mod . loop
\ 10 0 do temp # . i . loop
10 2 do temp # i mod . cond loop
;
: cond2 ( n - n )
10 2 do i
10 2 do i
mod .
loop cr loop
;
: main
\ numbers
cond2
\ plain
\ plain2
;
main
CR bye

There are several bugs and repetitions in your code. For example in your cond word you put 0 on the data stack then dup it and compare stack top value (which is 0) with 0. Of course, you will get true every time.
It seems that you try to write many words definitions at once and use them in your program without debugging carefully every single word. With Forth programming it is better to make (and debug) a few short words and then compose more complicated code with them. I would recommend you to read Starting Forth book which describes this approach very well.
Regarding your code -- it is better to rewrite it completely. Here it is:
: is-not-divided-by mod 0= INVERT ;
: check-prime-number true SWAP DUP 2 DO DUP I is-not-divided-by ROT AND SWAP loop DROP ;
: is-prime-number DUP 2 > IF check-prime-number ELSE DROP true THEN ;
: prime-numbers 1 DO I is-prime-number IF I . THEN LOOP ;
and now 10 prime-numbers will print you prime numbers from 1 to 9.

Related

SPSS/macro: split string into multiple variables

I am trying to split a string variable into multiple dummy coded variables. I used these sources to get an idea of how one would achieve this task in SPSS:
https://www.ibm.com/support/pages/making-multiple-string-variables-single-multiply-coded-field
https://www.spss-tutorials.com/spss-split-string-variable-into-separate-variables/
But when I try to adapt the first one to my needs or when I try to convert the second one to a macro, I fail.
In my dataset I have (multiple) variables that contain a comma seperated string that represents different combinations of selected items (as well as missing values). For each item of a specific variable I want to create a dummy variable. If the item was selected, it should be represented with a 1 in the new dummy variable. If it was not selected, that case should be represented with a 0.
Different input variables can contain different numbers of items.
For example:
ID
VAR1
VAR2
DMMY1_1
DMMY1_2
DMMY1_3
1
1, 2
8
1
1
0
2
1
1, 3
1
0
0
3
3, 1
2, 3, 1
1
0
1
4
2, 8
0
0
0
Here is what I came up with so far ...
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* MACRO SYNTAX.
* DEFINE VARIABLES (in the long run these should/will be inside the macro function, but for now I will leave them outside).
NUMERIC v1 TO v3 (F1).
VECTOR v = v1 TO v3.
STRING #char (A1).
DEFINE split_var(vr = TOKENS(1)).
!DO !#pos=1 !TO char.length(!vr).
COMPUTE #char = char.substr(!vr, !#pos, 1).
!IF (!#char !NE "," !AND !#char !NE " ") !THEN
COMPUTE v(NUMBER(!#char, F1)) = 1.
!IFEND.
!DOEND.
!ENDDEFINE.
split_var vr=VAR1.
EXECUTE.
As I got more errors than I can count, it's hard to narrow down my problem. But I think the problem has something to do with the way I use the char.length() function (and I am a bit confused when to use the bang operator).
If anyone has some insights, I would really appreciate some help :)
There is a fundamental issue to understand about SPSS macro - the macro does not read or interact in any way with the data. All the macro does is manipulate text to write syntax. The syntax created will later work on the actual data when you run it.
So, for example, Your first error is using char.length(!vr) within the syntax. You are trying to get the macro to read the data, calculate the length and use, but that simply can't be done - the macro can only work with what you gave it.
Another example in your code: you calculate #char and then try to use it in the macro as !#char. So that obviously won't work. ! precedes only macro functions or arguments. #char, in your code, is neither, and it can't become one - can't read the data into the macro...
To give you a litte push forward: I understand you want the macro loop to run a different number of times for each variable, but you can't use char.length(!vr). I suggest instead have the macro loop as many times as necessary to be sure you can deal with the longest variable you'll need to work with.
And another general strategy hint - first, create syntax to deal with one specific variable and one specific delimiter. Once this works, start working on a macro, keeping in mind that the only purpose of the macro is to recreate the same working syntax, only changing the parameters of variable name and delimiter.
With my new understanding of the SPSS macro logic (thanks to #eli-k) the problem was quite easy to solve. Here is the working solution.
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* DEFINE MACRO.
DEFINE #split_var(src_var = !TOKENS(1)
/dmmy_var_label = !DEFAULT(dmmy) !TOKENS(1)
/dmmy_var_lvls = !TOKENS(1))
NUMERIC !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (F1).
VECTOR #dmmy_vec = !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls).
STRING #char (A1).
LOOP #pos=1 TO char.length(!src_var).
COMPUTE #char = char.substr(!src_var, #pos, 1).
DO IF (#char NE "," AND #char NE " ").
COMPUTE #index = NUMBER(#char, F1).
COMPUTE #dmmy_vec(#index) = 1.
END IF.
END LOOP.
RECODE !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (SYSMIS=0) (ELSE=COPY).
EXECUTE.
!ENDDEFINE.
* CALL MACRO.
#split_var src_var=VAR2 dmmy_var_lvls=8.

Understand evaluation and loop [duplicate]

This question already has an answer here:
Suppressing Output MATLAB
(1 answer)
Closed 6 years ago.
Trying to understand this code :
A = [1 2 3]
T = A(:,1:end);
fprintf('\nvalues ', T);
A creates a Matrix of dimension 1 x 3
When I run this code, this is printed :
A =
1 2 3
Why is T not implicitly evaluated and printed to screen ?
I'm unfamiliar with this syntax : A(:,1:end); is this selecting the first column of Matrix and looping ?
The lines of code that are evaluated in screen "implicitly" are the ones that do not end with ;. The semicolon operator suppresses the printing of the result of that line.
In your code,
A = [1 2 3] % No semicolon -> print
T = A(:,1:end); % semicolon -> no print
The end keyword has nothing to do with the printing. Its a keyword very useful to do vetorized operations in Matlab.
Saying A(:,1:end) you are telling MATLAB " take all the values (:) from column indexes starting on 1 until the last column of the matrix end. Basically, in this case, all the values of A. You can try A(1:end,1:end) and check that returns the same thing.
For a more useful example, you might want all the matrix but the first row, then you would use A(2:end,:).

Perl - least common multiple

This code should do the LCM from N numbers.
I tried to put prints wherever I can in order to see where is the mistake. and I think is in:
if($vec[0] == $vec[$n-1]){
$resultado = $vec[0];
last;
}
But I can not make it work.
Could you please help me?
I'm a rookie with Perl.
Hope you can solve this problem.
Also I tried to change the variables but it does not work. I mean
$u = 0 , $w = $n-1;
FULL CODE
To get the LCM, you can split the task into multiple subroutines:
is_prime # returns true if the value is prime
roots # returns the roots of a number (all prime numbers that make up a value. Ex: roots of 12 are: 2, 2, 3)
LCM # takes a list of values. Extract the roots while the number is not prime. Store in a hash like and increment everytime we see the root
So we'll have a hash like:
%sub_total = (
VALUE => TIMES_FOUND,
2 => 2,
3 => 1,
);
We have another hash which is the total. If the sub_total hash has a key that is used more often than in the total hash, we add it to the total.
Finally, we loop through the total hash and and find the product using the algorithm:
for (%total){
$prod *= $_ ** $total {$_};
}
Note
I'll shortly attach the code I wrote for getting the LCM. It's not with me now here.

Sum of number in brainfuck

I would like to know if it is possible to calculate the sum of 1+2+3+...+k in brainfuck just with the number k at the beginning of the code?
For example is it possible to do 1+2+3 like this:
+++> (here the code creates a two add it with the three, create the one and add it)
Because I can do this : +++>++>+[<<+>>-]<[<+>-]< but if k=10000 how can I do this ?
Here is a simple version. Assume we name the first three cells y, temp0 and x. Then we can simply use this algorithm within a decrementing loop:
+++ # Input number (in fisrt cell)
[ # loop while first cell is not 0
>[-] # if second cell is null
<[>>+<+<-] # copy first cell in second and third and decrease it to 0
>[<+>-] # move second cell in first cell
<- # decrement input
] # go to begin of while loop
>> # the current cell now has the result
Note that this only works up to k = 22 due to the 8-bit limit. To output the number or deal with larger numbers, you'll have to use extra effort.
,[[>+>+<<-]>-[<+>-]<]>>.
A more concise and efficient algorithm than Ingo's. Uses three "slots"
|num|: original number; decremented each loop.
|temp|: copied back into |1| each loop
|total|: accumulates values each loop
+++ input |num|
[ while |num| is non-zero
[>+>+<<-] copy |num| to |temp| and |results|
>-[<+>-] copy |temp-1| back to |num|
< reset pointer
]
>>. output |total|
same explanation, but in more detail
+++ input |num|
[ while |num| is non-zero
[ until |num| is zero
>+>+ increment |temp| and |total|
<< return to |num|
- decrement |num|
]
>- goto |temp|, decrement
[<+>-] until |temp| is zero; decrement |temp|; increment |num|
< goto |num|
]
>>. goto |total|, output it

Conditional IF/ELSE Statement in Matlab

I was trying to make a simple statement with Matlab as follows:
if TF==1
disp('One'), break
else continue
end
... ... ...
... ... ...
But even if TF is not 1, when I run the command, it doesn't CONTINUE to the rest of the script!! Any help would be appreciated-- Thanks
The continue statement has a very different meaning. Within a loop, like a for or while loop, continue instructs to skip the current round and continue with the next iteration in the loop. So if you remove continue, you will see the behavior that you are expecting. Here is an example:
for k = 1 : 10
if k == 4
% skip the calculation in the case where k is 4
continue
end
area = k * k;
disp(area);
end
When the loop iterates at k == 4, the block calculating the area of the corresponding square is skipped. This particular example is not very practical.
However, imagine you have a list of ten file names, and you want to process each file in this loop "for k = 1 : 10". You will have to try and open each file, but then if you find out the file does not exist, an appropriate way to handle it would be to print a little warning and then continue to the next file.