functionprimeskdb+

Finding prime numbers kdb, discussion about projection and functions


So I am trying to create a function that finds all the prime numbers below a certain number.

This is the code I have written which doesn't work, but will help me explain how I am trying to solve it. I will fix the manual checking for 0,1,2 later.

primes: enlist 2
g: h[;primes]
g'[3 + til 100-2]

h:{[x;y] z: x mod/: y; bool:(0 in z)=0b; if[bool; `primes set primes,x ]; }

So what I want to do is, use the each (') operator to run this function h for each element in 3+ til 100-2. However, I want it to continue using the primes variable not in an each way. The if statement will execute if there is no 0 in z as this means x is prime. Then in the if statement, I would like to join x to the primes list.

Loop 1: x:3 y: enlist 2 In the if statement, it will join 3 to primes

loop 2: x:4 y: 2 3 if statement will not execute

loop 3: x:5 y: 2 3 In the if statement, it will join 5 to primes

loop 4: x:6 y: 2 3 5 if statement will not execute

Thanks for your help!


Solution

  • Your logic works, and can be tidied up a little as:

    q)primes:enlist 2
    q)h:{m:x mod/:primes;bool:(0 in m)=0b;if[bool;`primes set primes,x];}
    q)h'[3 + til 100-2];
    q)primes
    2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
    

    Some differences to yours:

    1. If you project your h with input primes, e.g. g:h[;primes] then that primes input is fixed at that point in time, it will not vary for each iteration. So your y in your function is always fixed at just 2.

    I got around that in this example by simply referencing the global primes variable (which isn't fixed).

    1. I avoided using z as a variable within the function as it is generally bad practice since z is more commonly used as the default/implicit third input variable in a function.

    Sticking with your logic, a more conventional iterative approach which doesn't require a global primes variable would be:

    q){$[not 0 in y mod/:x;x,y;x]}/[2;3 + til 100-2]
    2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
    

    This uses over (/) to iterate.

    This still isn't the optimal way to get primes, for that this might be optimal: https://github.com/KxSystems/kdb/blob/master/greplin.q#L6

    q)p:{$[x<4;enlist 2;r,1_where not any x#'not til each r:p ceiling sqrt x]}
    q)p 100
    2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97