5 ms·
This problem has a nice array solution: q)where mod[;2] sum 0=til[500] mod/: til[500] 0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361
by geocar 7y ago
This problem has a nice array solution:
q)where mod[;2] sum 0=til[500] mod/: til[500]
0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484
q){x*x} til ceiling sqrt 500
0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484
but I think it's very interesting to look at them side by side: Do you see the "triangle" in the above that suggests the sqrt-solution?
q)0=til[500] mod/: til[500]
00000000000000000000000000000000000000000000000000000000000000000000000000000..
11111111111111111111111111111111111111111111111111111111111111111111111111111..
10101010101010101010101010101010101010101010101010101010101010101010101010101..
10010010010010010010010010010010010010010010010010010010010010010010010010010..
10001000100010001000100010001000100010001000100010001000100010001000100010001..
10000100001000010000100001000010000100001000010000100001000010000100001000010..
10000010000010000010000010000010000010000010000010000010000010000010000010000..
10000001000000100000010000001000000100000010000001000000100000010000001000000..
10000000100000001000000010000000100000001000000010000000100000001000000010000..
10000000010000000010000000010000000010000000010000000010000000010000000010000..
10000000001000000000100000000010000000001000000000100000000010000000001000000..
10000000000100000000001000000000010000000000100000000001000000000010000000000..
10000000000010000000000010000000000010000000000010000000000010000000000010000..
10000000000001000000000000100000000000010000000000001000000000000100000000000..
10000000000000100000000000001000000000000010000000000000100000000000001000000..
10000000000000010000000000000010000000000000010000000000000010000000000000010..
10000000000000001000000000000000100000000000000010000000000000001000000000000..
10000000000000000100000000000000001000000000000000010000000000000000100000000..
10000000000000000010000000000000000010000000000000000010000000000000000010000..
10000000000000000001000000000000000000100000000000000000010000000000000000001..
10000000000000000000100000000000000000001000000000000000000010000000000000000..
10000000000000000000010000000000000000000010000000000000000000010000000000000..
..
Isn't that beautiful? This is really illustrative of what I think is valuable in learning array programming, and whilst I've noted it previously on HN[1], this might be an even better example. Try writing the algorithm in C or Python:
void main(){
int i,j,k;
for(i=0;i<500;++i) {
for(j=k=0;j<499;++j)if(!(i%(1+j)))++k;
if(k%2)printf("%d ",i);
}
puts("");
}
Now because I can't see the shape of the data so easily anymore, I might not so quickly recognise the optimisation waiting for me in that code, especially if this spanned more than a screenful (because e.g. we were doing something else besides printing the results)
[1]: https://news.ycombinator.com/item?id=16851862 https://news.ycombinator.com/item?id=16851862
- danbruc 7y agoBeing pedantic, there is no room zero, so it should be 1 _ til 500.
- geocar 7y agoYou can try that, but it produces the wrong answer: "where" is still zero-based. You would also need 1+ i.e. q)1+where mod[;2] sum 0=(1_til 500) mod/: til 500 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484 ...but this is not a huge bother for me: 0 mod 0 is 0N which doesn't equal zero, and I think the extra 1_ or 1+ distracts somewhat from the point I'm trying to make.
- msla 7y agoI can read the C++ (not C), though, and improve it, whereas the two lines above are impenetrable. I can also lift the core of the C++ code into a function and reuse it, which doesn't appear possible in the other language.
- geocar 7y ago> I can read the C++ (not C), though, and improve it, Can you give an example of some improvements you see that are directly obvious from the C code? I'm especially interested in a process that reveals the sqrt optimisation. > whereas the two lines above are impenetrable. It takes practice to learn a new language. For now, you will have to take my word that the former of the lines is almost a literal translation of the problem, and to an experienced q developer, directly suggests the second line. I hoped the illustration would suggest this, but communicating alien things is hard. Languages that have that property are extremely valuable to me: There are a lot of languages that have a nice notation leading from problem to code (lisp, haskell, etc; at least some of the time) but it is much more rare that we have a notation that directly suggest further (better) notations, and myself having programmed in C, C++, Perl, Python, Java, Forth, Fortran, Cobol, Lisp, and so on for decades, I'm telling you that this seems to happen more with array languages than with any other language or language-family that I've had experience with. If that intrigues you, I can try and give you a crash course: - til x is the vector of integers from 0 to x. In C it's a little like: r=calloc(sizeof(int),x);for(i=0;i<x;++i)r[i]=x; - x mod y is modulo. Similar to x%y in C, but it generalises to vectors. - x mod/: y shows each-right (/:) which composes to the operator on the left. This builds a 2d array of each x argument (columns) mod each y argument (rows). - til[x] mod/: til[x] is thus the 2d array of integers from 0 to x mod each right the same list. - x=y is equals. Similar to x==y in C, but it generalises to vectors. - 0=til[x] mod/: til[x] is thus a bitmap of locations where (columns:0..x) mod (rows:0..x) = 0 - sum adds up the values in a vector. applied to a 2d array (including a bitmap) returns the sum of each column. - functions are written with curly braces. In a function, x is the first argument, y is the second. - {x*x} is thus a function that squares its result. - mod[;2] is a projection. It is actually the function {x mod 2} - where returns the locations of 1's in a list. - where mod[;2] ... is thus the locations of odd values. - sqrt x returns the square-root of x, expressed as a float. this too generalises to vectors, but we do not take advantage of this. - ceiling x is the same as ceil(x) except it too generalises to vectors (we aren't using this). With that in hand, you should be able to carefully decode each line: They're read from left to right, and q composes easily. > I can also lift the core of the C++ code into a function and reuse it, which doesn't appear possible in the other language. That's generally true for Python or Java, but q programmers have an excellent C binding. It's as simple as: k(0, "{where mod[;2] sum 0=til[x] mod/: til x}", kj(n), 0) - k(f,s,x,[y,[z,...]],NULL) calls into k. f must be zero (in-process) in this case. s is the script. x, y, z, (etc) are arguments terminated by null. - kj(n) returns a variant (type tagged) from a long long.