« first day (373 days earlier)      last day (1162 days later) » 

ngn
12:08 PM
@ksi at bitbucket you mentioned you had studied some of my code. i'm curious, did you notice anything that could obviously be done in a simpler way?
 
12:25 PM
i have free spots for %c (uint8) and %i (int32). %f is sqrt, +c / -c is toupper/tolower. any idea for %c and %i? (int sqrt is not common enough imo)
maybe bitwise not.
 
@ktye upper/lower for strings is cute
@ktye int sqrt came up a few times in @ngn's eulers
 
ngn
@chrispsn i was just about to write the same comment :)
 
split int and fractional components?
 
@chrispsn %i must be i->i. %f is already sqrt.
 
d'oh
Idk I think consistency is good - same basic function for both i and f
And yeah maybe a bit wise operation for chars
 
12:36 PM
maybe i don't do enough eulers. but i never needed int sqrt.
 
On a separate note I'm coming around to Arthur's original idea for k7 filter groups.google.com/forum/m/…
 
ngn
@ktye one typical use is to decide what the size of the prime sieve should be
 
The speed diff in the implicit each is not great twitter.com/kcodetweets/status/1239121676643602437?s=21
 
@chrispsn which filter do you mean? f#x works on the array the same way as x@&f x . Which is apl select: (f x)/x
 
ngn
@chrispsn there should be a 0 1\ or 0 1\: for splitting the whole and fractional parts (depending on dialect and atw's mood). is it common enough to deserve a single-char primitive?
 
12:41 PM
@ktye I think it's more like x@&f'x
@ngn no idea, just brainstorming
 
@chrispsn why each? to use it for tables?
 
@ktye I think so. That's the status quo
 
it could also do each only for dicts/tables and otherwise apply to the vector itself.
 
@ktye it should have consistent behaviour for tables and other kind of list imo
@ktye one downside of +c is that it's not atomic
 
12:57 PM
@chrispsn other primitives do the same, operate on a vector but apply to each within a list.
 
But it would mean flip for a table
 
yes, i currently use +x as absolute value and don't have a primitive for transpose/flip.
 
Ahh
Half-tempted to say flip should be in z.k instead of being a built-in
but... don't want to make flippant suggestions
But more seriously I used it a lot in some AoC but it's really not a good habit
 
ngn
1:14 PM
@chrispsn how would you implement it? ,'/,''?
 
 
5 hours later…
ksi
6:09 PM
@ngn not yet, i am still going through the parser and bytecode complier, where i usually got stuck at the meaning of some internal verbs, e.g. au_xxx, bm and beyond in the bytecode enum. and it's not that easy to spot cheaper alternative in this part of codebase i geuss. maybe there is a little chance when it comes to the implementation of verbs.
 
ngn
@ksi i use "u" for unary verb, "v" for binary verb, and "w" for adverb. "au_" stands for "array of type unary verb" (or "allocate.." but there's no allocation really - all the information is encoded in the tagged pointer)
au_out is a pseudo-verb corresponding to the new syntax i borrowed from k7 and k9: expr1 \expr2
this prints the result from expr2 before evaluating further - convenient for debugging
au_cmd is for \syscmds
au_plc is a placeholder for missing args in projections, similar to one of the uses of :: in k5-6
av_com builds compositions, like '[f;g] in k5-6
av_mkl is "make list". i think the real k somehow reuses ,: (enlist) for that but i ended up needing a separate verb
bm bM - local&global modified assignment (a[i]+:b)
bl bL - make list and destroy list, the latter used for (a;b):c
ba - apply n-adically
bP - make projection
bz - branch if zero (i.e. if falsey)
bj bp br - jump pop return
bc - load constant (128 such instructions)
 
ksi
6:25 PM
@ngn thanks, that's very helpful. maybe you can put these info in the readme.txt, too. that will be very useful for newcomers.
 
ngn
@ksi i fear i might forget to update them next time i decide to rename everything. maybe a comment in b.c (the bytecode compiler&vm) would be better if i can compress it well enough
 
ksi
that's fair, i can remind you if i am still closely look at ngn/k at that time:)
Also, i did try to modify some small pieces of code when i think i got the meaning of a function, e.g. in memcmp@m.c, F(n,I d=*p++-*q++;P(d,d))0) seems to able to replace by F(n,P(*p++-*q++,1))0). would you mind small suggestion like that, though i could misunderstand its meaning since i only gauge the equivalence based on your test cases only:) @ngn
 
ngn
6:45 PM
@ksi you're right. in general memcmp() is supposed to discern beween negative and positive results, depending on how the first mismatched bytes differ, but i use it only to implement x~y so here it doesn't matter. thanks
 
ksi
gotcha, will keep looking at it.
 
ngn
@ksi it seems slightly faster now :) i'm interested in any suggestions, no matter how small
there are very few people in the world who aren't disgusted by this ultra-concise coding style
@ksi may i ask, what is your motivation to study the code?
 
ksi
7:01 PM
lol, i can imagine why people don't like it. i find it acceptable except for the ultra short name of vars and funs.
i do a lot coding in q/kdb at work. i am always interested in making q code faster. someimes, i got to a point that i need modify the language to be able to do it. ofc, i wouldn't do that at work, but as a hobby, it's fun to implement my own version of k. but i know little about how to write a fast interpreter. it couldn't be better to have this open source implementation, so thanks @ngn
 
ksi
7:24 PM
@ngn Also, why do you chose A to be L, rather than UL, and have it converted to UL for getting and setting the tagged info. i am not sure which is faster though.
 
ngn
@ksi i haven't thought about that, really
afaik signed-unsigned casts are no-ops for types of the same size, but it might make the c code look less ugly
@ksi i had declared slc_() the wrong return type - fixed now. other than that, the binary is exactly the same with TD L A; and TD UL A;
 
ksi
7:45 PM
okay
and how about L pl(C**p)_(I m=**p=='-';*p+=m;(1-2*m)*pu(p)) -> L pl(C**p)_(?**p=='-'?++*p,-pu(p):pu(p)) in p.c, ofc pd as well @ngn
 
ngn
@ksi it's tempting because it's shorter in c, but it generates more machine code
(without the ? before **p==..)
i can't detect a significant difference in performance
 
ksi
@ngn oh, i didn't know that. i am also curious why did you have to define mmap_ in asm? is it related to -nostdlib?
 
ngn
@ksi yes, all syscalls are in asm. most of them are macros defined in k.h
mmap is special because it has many (6) arguments. others have up to 3
-nostdlib also means that _start() has to be in asm too
 
ksi
8:01 PM
@ngn okay, asm for syscall is beyond my knowledge, do you have some good ref on that?
 
ngn
@ksi i can't think of a single link to recommend. i've gathered information from various places - blogs, stackoverflow, random web searches..
basically, the x86_64 calling convention is very similar to the calling convention for functions (integer args go into rdi,rsi,.. and the result is in rax) except that one of the args uses a different register - r10 instead of rcx
i've no idea why it was designed that way
to make the call itself, there's a "syscall" instruction
so, very straightforward, if it wasn't for the weird asm() syntax..
if you look at kparc.com/b/A.S - arthur has taken the simplest possible way out of this. he declares functions that act as wrappers around the syscalls, taking care only of the rcx/r10 oddity
the drawback is that there's the function call overhead, but that's probably dwarfed but the cost of a syscall anyway
i fought this problem to the end and i made my syscalls inline (no wrapper functions), but now i have much more than 3 lines of code dedicated to this and not much advantage performancewise, so.. not sure if it was worth it
 
ksi
8:23 PM
thanks for the detailed explanation, arthur's way does feel simpler for understanding. @ngn
 
ngn
8:37 PM
@ngn correction: "the x86_64 calling convention" - i meant "the x86_64 syscall calling convenion" there
 
9:01 PM
@ngn nice! i had this for tolerant flip: {m:(i:|/#'x)$/x;m@\/!i}. yours is faster than my intolerant flip: {x@\/!|/#'x}
 
ngn
@chrispsn still, i expect it to be much slower than a built-in flip, because mine has to enlist each individual element of the matrix before it starts concatenating them
 
also the tolerant flip above doesn't repeat atoms
 
ngn
 a:{1000?0}'!1000; f:,'/,''
 \t:10 +a
76
 \t:10 f a
851
i don't think this is gonna fly
argh.. i could've written 1000?'&1000 instead of {1000?0}'!1000 :) too late to edit
 g:{m:(i:|/#'x)$/x;m@\/!i} /yours is better
 \t:10 g a
679
 
9:20 PM
i used {(,/x[;!n])@(n*!#x)+/:!n:|/#:'x} in i2. it may need atomic extension, like k9
 
ngn
@ktye interesting idea
and the performance matches that of primitive flip (in k9)
 
does it work for you? how fast is it?
 
ngn
9:36 PM
 a:1000?'&1000;f:{(,/x[;!n])@(n*!#x)+/!n:|/#'x}
 f[a]~+a
1b
 \t:10 +a
72
 \t:10 f a
74
 
that's k9? what about kn?
 
ngn
@ktye kn?
 
ngn
 
ngn
@ktye my x[;!n] is wrong
@ktye if you remove [;!n] to make it intolerant, your flip beats the original flips in both ngn/k (by a lot) and k9 (by a little) :)
well, at least for the 1000x1000 int matrices i test with
let's see if we can make it even better..
 
 
1 hour later…
ksi
11:09 PM
@ktye what does x[;!n] mean in k9? i suppose it just means flip, right? i.e. take the columns out of a matrix. @ngn ngn/k works as i expected, it's slow though.
 
that's matrix indexing in k7 and fills missing elements, e.g:
2019-09-25 14:44:44 4core 7gb avx2 © shakti l test
x:(,1;2 3)
x
,1
2 3

x[;0 1]
1 Ø
2 3
it works the same in k9.
 
ksi
@ktye It feels inconsistent for me... I would prefer f:{(,/x@\:!n)(n*!#x)+/:!n:|/#'x} in ngn/k. I.e. f:{(,/x@\!n)(n*!#x)+/!n:|/#'x} in k9
 
ngn
11:27 PM
@ksi why inconsistent? a missing index is treated like "all"
 
ksi
Shouldn't x[;0] gives the first column of a matrix? i guess it depends on how it vectorize it when the second argument is a list.
 
ngn
@ksi yes: x[;0]~x[!#x;0] and x[;!n]~x[!#x;!n]
 
ksi
@ngn okay, somehow you implement something what i expect, which is not consistent in terms of function projection. my bad:)
 
ngn
11:49 PM
@ksi it works the same way in apl too: ⍴a[i;j;..] ←→ (⍴i),(⍴j),.. with missing indices treated like ⍳N for N=the length along the corresponding axis
 

« first day (373 days earlier)      last day (1162 days later) »