News for hackers. Stuff that matters.
Re:Is the room open? by geocar on Monday February 10, 2020 @07:34AM (#22288534)
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

Re:Is the room open? by danbruc on Monday February 10, 2020 @08:11AM (#22288781)
Being pedantic, there is no room zero, so it should be 1 _ til 500.
Re:Is the room open? by geocar on Monday February 10, 2020 @08:31AM (#22288910)
You 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.
Re:Is the room open? by msla on Monday February 10, 2020 @10:36AM (#22289975)
I 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.

Re:Is the room open? by geocar on Monday February 10, 2020 @01:44PM (#22291941)
> 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.

Re:Is the room open? by msla on Monday February 10, 2020 @05:12PM (#22293957)
> Can you give an example of some improvements you see that are directly obvious from the C code?

Comments and good variable names, to begin with, which should be mandated by any style guide.

If you can't give your variables readable, understandable names you don't understand your code and nobody else is going to, either.

Re:Is the room open? by geocar on Tuesday February 11, 2020 @03:29AM (#22296973)
Well that was disappointing.

Anyway, good luck with things.

Re:Is the room open? by msla on Tuesday February 11, 2020 @11:23AM (#22299659)
Disappointing? It's a simple, actionable comment.

It's also the bare minimum required to have readable source code.

Most people don't like reading stuff that looks like it came out of a particularly aggressive obfuscator.