Works nicely on Linux where the syscall interface is explicitly stable, but on many (most?) other platforms this is not the case.
> There Is No Heap
I don't understand what this means, when it's followed by the definition of a heap allocation interface. The paragraph after the code block conveys no useful information.
> Null-terminated strings are the devil’s work
Agreed! I also find the stance regarding perf optimization agreeable.
Looks like the default allocator uses mmap(2) for every single allocation, which is horribly inefficient - you map a whole PAGE_SIZE worth of memory for every tiny string. Aside from just wasting memory this will make the TLB very unhappy.
It looks like sp_log's string formatting is entirely unbuffered which results in lots of tiny write syscalls.
Oh man. Oof. I'm sure there must be some repository out there that has an AGENTS.md but isn't pure slopcode, but I haven't seen it yet. The number of people who can be trusted to vibe code "responsibly" is probably about the same as the number of people who can be trusted to write memory safe C.
As noted in my other comment though, some interesting decisions and interfaces do point to some degree of human intervention. I have recently written a similarly sized WebAssembly runner in C using agents (feel free to review: [1]) so I'm pretty certain that agents simply don't do that kind of things themselves...
"How bad can it be, I mean I know that numerics are not many people's strong suit, but..."
... ... ... oh wow, the math functions are really bad implementations. The range reduction on the sin/cos functions are yikes-level. Like the wrong input gives you an infinite loop level of yikes.
It is not part of the core library. It is certainly not meant as a reference-level implementation of math functions. It's there so you can write an easing function for a game without pulling in libc. It seems like its existence has offended you. If that's the case...I'm sorry? At every possible point, I note as loudly as possible exactly what that library is. I found your tone extremely dismissive and disrespectful and I don't care to engage with that any more than I already have.
> It is not part of the core library. It is certainly not meant as a reference-level implementation of math functions. It's there so you can write an easing function for a game without pulling in libc.
I saw the note and ignored it because it's not actually a repackaging of HHM. It simply happens to define a few vaguely similar functions. It doesn't reuse the naming conventions (MulVec3f vs vec3_scale), it doesn't reuse the interface (see SP_MATH_IMPLEMENTATION), and it's missing genuinely useful bits like the matrix functions.
Moreover, the quality of what's been added is significantly worse. Look at sp_sys_expf:
f32 sp_sys_expf(f32 x) {
f32 result = 1.0f;
f32 term = 1.0f;
for (int i = 0; i < 20; i++) {
term *= x / (f32)(i + 1);
result += term;
}
return result;
}
I can't imagine a good reason why anyone (even an LLM) would ever write a 20th order taylor series for expf. A single FMA can improve on this and have capped relative error to boot, and that's not even a good way to do it. See what happens with your function at +-10 for comparison. At the f32 limit of 88, you achieve an honestly impressive 100% relative error.
Also, because sp_math doesn't use FMAs, your library isn't reproducible. Different compilers will produce different values. Reproducibility is a pretty nice property in games.
I don't like that slopcode angle either, but unfortunately I have to say that you do have picked a wrong library to bundle. For example, it's almost likely that there is a correct (not just accurate enough, but correct) implementation of sqrt in your CPU because IEEE 754 mandates that. Unless you're doing softfloat you simply want to wire it via asm.
Not just the TLB, but the L1 D$ will be very unhappy as well. All heap objects being page aligned on most microarchs ends up making every object start at cache set 0 because the set determination ends up being indexed off of the offest within a page so that the TLB lookup can happen in parallel with the set load.
The point of the library is that you do not call the low level allocation primitive to allocate a single string. Of course, in simple programs which exit immediately, there is no difference between using a page allocator and a heap allocator. In real programs, I use an appropriate allocator for the allocation rather than making arbitrary calls to malloc(). In the sp.h examples, I use the page allocator to keep freestanding Linux simple. I could swap out a single line to be backed by an arena, but it misses the forest for the trees.
sp_log() writes directly to an IO writer. An IO writer can be buffered or unbuffered, but is unbuffered by default. This is a feature, not a bug. Have a look through the IO code!
q> sp_log() writes directly to an IO writer. An IO writer can be buffered or unbuffered, but is unbuffered by default. This is a feature, not a bug. Have a look through the IO code!
Why is the unbuffered default? Is there any thoughts on this?
Jesus! Claude could've told this guy all these things. People underestimate how much the average malloc implementation does and how many considerations it makes. Or how much IO sucks.
Thanks for reading. "There is no heap" is meant to say that your mental model of memory shouldn't be one heap from which all memory is pulled. It should be many heaps, owned by many different allocators and providing different semantics. Hence the opinionated stance of the library; there is no allocation function that does not force you to specify the specific heap you want to allocate from. I'm sorry if I didn't explain that well.
As far as the syscall thing, it's actually quite interesting. NT is also extremely stable. Likewise for the stock Darwin syscalls on macOS. In practice, though, Windows loads kernel32.dll automatically, so there's no drawback in using it when appropriate. I still call directly into NT sometimes (mostly to skip complex userspace path translations that aren't useful). On macOS, you are likewise forced to link to libc (libSystem.dylib), and so I usually just end up using the syscall-wrapper libc functions there.
> Works nicely on Linux where the syscall interface is explicitly stable, but on many (most?) other platforms this is not the case.
There is a footnote on this saying as much:
> 3. Where “syscall” means “the lowest level primitive available”. On Linux, it’s always actual syscalls. On Windows, that’s usually NT. On macOS, it’s usually the syscall-wrapper subset of libc because you’re forced to link libc and it’s not quite as open as Linux (although there is a rich “undocumented” set of APIs and syscalls that are very interesting).
That might work on FreeBSD but is pretty well guaranteed to break on OpenBSD. (Dunno about Net and Dragonfly) (I'd caution that treating the BSDs as a monolith is likely to end in errors; they're quite diverse.)
The "definition of a heap allocation interface" indicates that there is no standard heap. Instead, there's a standard interface for the use to define their own heaps. Any standard library function that needs to allocate will take a sp_allocator_t parameter, and use that to allocate. As opposed to e.g. strdup, which hard-codes a call to malloc internally. Sp.h's strdup-alike would take an sp_allocator_t as input and call into that to get the memory it needs.
A C++ programmer might describe this as "PMR, but not default-constructible. And std::stable_sort takes a PMR allocator parameter. And PMR is the default, and there's no implementation of std::allocator (or new or delete)."
Take a look at the user's history, it's more obvious in context. It has a lot of claude-specific tells which are noticeable if you've spent time working with claude. AI-generated comments are against the HN guidelines https://news.ycombinator.com/newsguidelines.html#generated
not AI slop, simply a copy paste if the abstract of the paper. journals in our field limit the allowed number of words, so the style can feel « unnatural » even when human-written
> resolves into "cross-venue infrastructure" — which is also a more durable edge than within-venue alpha
anybody who actually trades knows that on these markets, "cross venue infrastructure" (aka vibe coding some exchange api integrations) is much less important / durable than actual alpha.
That sounds plausible. Not a trader so I wouldn't know. Saying at least a little about what's actually wrong with it seems more useful than just saying it's slop, which gives me very little info over just a downvote.
it's pretty easy to write basic trading api connectivity. the hard part is knowing what trades to send
even if we are very charitable and assume the comment refers only to like high-engineering-effort infra for trying to be super competitive on latency, that's still like the opposite of a durable edge, since everybody is looking at it. there's very little "hidden" knowledge and it's mostly a matter of elbow grease and careful engineering.
arbitrage is a rather overloaded word that people use for all kinds of strategies but yes, I predict most of the most profitable and consistent accounts are not actually attempting to forecast the outcome of these markets from first principles
no fuck that. We should definitely complain about AI written content, and we should ban anyone who wants to keep people ignorant of time wasting bs comments.
As a side note, the AI popularized usage of the word 'clean' to denote proper is physically revolting to me.
Yes, just like the "don't say HN is becoming reddit" rule. If you think it's AI downvote or flag and move on, reading "this is AI" over and over all over the internet without any substantiation is tiresome.
it's only "better than human comments" if you have no idea what profitable trading looks like. it's a very-very thin mildly convincing veneer over what is fundamentally slop.
Not really. Not all players in prediction markets are rational players. A good chunk of it are there for entertainment, and analyze things incorrectly; you can take the other side of those trades, and you won't need to predict the future.
Stylistic tells: "The tool-call ambiguity point", "—", "the negative space", "The retry-nudge layer", "the right shape", "→", "context drift"
Correctness tells: find exits with 0 when no matches were found, not 1. LLMs do get confused about tool call results sometimes but it's nowhere near as bad as needing "[manual corrections] multiple times an hour".
Contextual tells: see their account history and other comments.
Right, good example, and both GCC and Clang offer well understood parameters for deciding, per compilation unit, what behavior you want for signed overflow (-fwrapv, -fno-strict-overflow, etc), so in reality it's quite far from spooky arbitrary nasal demons.
> But also, what you describe would be incorrect, since two <MAX values can add to a value that is >MAX, and overflow
I was maybe unclear. I meant, if you know a sum can introduce overflow (because you have a check right after), why not check the inputs before doing the sum, instead of checking the sum?
(y > 0 && x > INT_MAX - y)
|| (y < 0 && x < INT_MIN - y)
and hope the optimizer turns it back into just checking the result. Or you use -fwrapv to concretize the ISO ambiguity and specify the natural two's complement semantics, checking overflow with the classic Hacker's Delight formula;
((x ^ s) & (y ^ s)) < 0
But the best way is to use the intrinsic __builtin_add_overflow or, depending on compiler support, its C23 standardization via <stdckdint.h> and ckd_add etc.
That's not what the previous comment is referring to. They're referring to false positives, i.e "Gemini did not generate this (or process it) yet it says SynthID confirmed"
So imagine the damage you could do to an artist by having Gemini flag it then saying “see here’s the proof they’re using AI art!” That person would get eaten alive.
I see they use those cheapo Chinese RF modules (SA818). I've seen those also with SDR input/output, that's interesting. The underlying chip is very similar: The chip that will be used in this module is the RDA1846. This is a chip that's in most Chinese handhelds and is internally fully SDR but it decodes to analog. There's also the RDA1847 with similar pinout which offers the raw SDR stream and can thus be used for any mode, but with the added complexity of having to do the SDR decoding externally.
That means that this design could probably also be modified to do DMR. Though the SDR side might be a little bit too much to ask of an ESP32. On the other hand, it is only a very low bitrate signal.
Works nicely on Linux where the syscall interface is explicitly stable, but on many (most?) other platforms this is not the case.
> There Is No Heap
I don't understand what this means, when it's followed by the definition of a heap allocation interface. The paragraph after the code block conveys no useful information.
> Null-terminated strings are the devil’s work
Agreed! I also find the stance regarding perf optimization agreeable.
reply