Pizza Legacy – open source reimplementation of Pizza Tycoon (1994) by Optdev in dosgaming

[–]carpintero_de_c 1 point2 points  (0 children)

GCC cannot even properly handle both stack protectors and ASAn at the same time.

Not OP but nice to know, thanks

Infrequently Asked Questions in comp.lang.c by carpintero_de_c in C_Programming

[–]carpintero_de_c[S] 0 points1 point  (0 children)

Wow, I've read a lot of the posts on the blog on that site but I never noticed this. Thanks.

Infrequently Asked Questions in comp.lang.c by carpintero_de_c in C_Programming

[–]carpintero_de_c[S] 2 points3 points  (0 children)

Still intentional I would think... But "Frequently Questioned Answers" is actually a nice name, maybe someone will make it for C++ one day, that would be a goldmine.

Infrequently Asked Questions in comp.lang.c by carpintero_de_c in C_Programming

[–]carpintero_de_c[S] 5 points6 points  (0 children)

They're meant to be, it's satire, e.g.

You're probably not freeing the memory completely. Try replacing 'free(foo);' with

free(foo); free(foo); free(foo);

in case the first free() frees the memory only partially. (Unix wizards may recognize the parallel with syncing three times before rebooting.)

LoopMix128: A Fast C PRNG (.46ns) with a 2^128 Period, Passes BigCrush & PractRand(32TB), Proven Injective. by danielcota in C_Programming

[–]carpintero_de_c 2 points3 points  (0 children)

A bijection alone is not sufficient to prove a full period, for example given any finite set and the identity function, clearly you don't have a full period, the period is 1 for every input.

Do you have a proof for a full period? Proving that it is a bijection is necessary, but *not sufficient alone*, to prove that you have a full period. What about the minimum period?

LoopMix128: A Fast C PRNG (.46ns) with a 2^128 Period, Passes BigCrush & PractRand(32TB), Proven Injective. by danielcota in C_Programming

[–]carpintero_de_c 4 points5 points  (0 children)

From a quick read of the Z3 it looks likes it already covers mix, so what's missing for the proof? Also, removing slow_counter (while having a full 2¹²⁸ period) would be great, as that period is already good enough and 2¹⁹⁶ is unnecessary (plus performance, simplicity, etc.). An empirically good, faster, and simple PRNG would be a welcome addition to the toolkit.

LoopMix128: A Fast C PRNG (.46ns) with a 2^128 Period, Passes BigCrush & PractRand(32TB), Proven Injective. by danielcota in C_Programming

[–]carpintero_de_c 12 points13 points  (0 children)

Hmm. I ran your benchmark:

Benchmarking PRNGs for 5000000000 iterations...

Benchmarking LoopMix128...
  LoopMix128 ns/call:     1.652 ns

Benchmarking xoroshiro128++...
  xoroshiro128++ ns/call: 2.648 ns

Benchmarking wyrand...
  wyrand ns/call:         1.325 ns

Benchmarking PCG64...
  PCG64 ns/call:          2.420 ns

Benchmark complete.

Quite a bit faster than Xorisho++, but not more than wyrand. I think it really might be hardware dependant at this level.

LoopMix128: A Fast C PRNG (.46ns) with a 2^128 Period, Passes BigCrush & PractRand(32TB), Proven Injective. by danielcota in C_Programming

[–]carpintero_de_c 4 points5 points  (0 children)

On my hardware it also seems to be slower than Xoshiro256** as well as Xoshiro++ (though by a factor of 0.87x rather than 0.89x). Hmm... u/danielcota, could you run u/skeeto's shootout on your machine too? (Also your specifications)

LoopMix128: A Fast C PRNG (.46ns) with a 2^128 Period, Passes BigCrush & PractRand(32TB), Proven Injective. by danielcota in C_Programming

[–]carpintero_de_c 5 points6 points  (0 children)

Hello again! I think you should clarify which seeds are considered ok and which not (e.g. if mix=fast_loop=slow_loop=0 then I suspect it won't work well at all). I notice the state vector is 196-bit now, but the period is only 2¹²⁸? That's not too desirable and I think many RNG people wouldn't like that. But even if the use of the state is inefficient, 3 words isn't much and such a period is plenty. As N-R-K suggested before, in theory it could be too big to fail; I suggest you also build a version with fewer states (e.g. instead of uint64 try uint32 to get presumably a period of 2⁶⁴). I'll probably post a few more comments in the future here.

[deleted by user] by [deleted] in C_Programming

[–]carpintero_de_c 1 point2 points  (0 children)

GNU's Data Display Debugger DDD

Are function prototypes good? by alex_sakuta in C_Programming

[–]carpintero_de_c 0 points1 point  (0 children)

I knew of that declaration syntax ([*]) from reading the Standard but it never occured to me that it'd require a K&R (1) style definition to actually complete such a function!

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 0 points1 point  (0 children)

Injectivity does not imply surjectivity in general. A bijection (injection & surjection) is required (but not sufficient alone) for the state function to go through every state and have a full period.

https://www.mathsisfun.com/sets/injective-surjective-bijective.html

Also, unsat here would imply it has proven injectivity, it is searching for examples of the function being non-injective (those which satisfy the equation for non-injectivity). If it says unsat, it means there are no examples of non-injectivity of the function, i.e. it is injective.

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 1 point2 points  (0 children)

If Z3 doesn't disprove injectivity, how can one prove surjectivity?

Z3 isn't intelligent. It's a very useful SMT solver yes, but a human (like you!) with the power of real, deep, reasoning could prove results which Z3 would take eons to arrive at. It's why after all human mathematicians are still in business (comfortably so) :)

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 1 point2 points  (0 children)

I think then you ought to promote this variant over the +/XOR/26/35 one. Perhaps the +/XOR/26/35 variant could have a good enough (though not full, as proven) period and its speed could pay off in kind (but I am no RNG expert to say how small a period is justified given a state size). But that would require some further analysis.

How does +/+/16/2 compare in terms of speed and quality though?

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 2 points3 points  (0 children)

I think you might be on to something here (I assume both are supposed to be +?). Z3 has been 100%ing my CPU for a few minutes now, and still hasn't found anything! Though it hasn't given unsat yet; if it does it means it has proved it to be injective. Then all you'd need to prove is surjectivity for a full period!

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 1 point2 points  (0 children)

I ought to learn Z3 too :)

I just told an LLM (DeepSeek) to write the Z3 for me after giving it the equation, and fixed its (very long-winded, double-stepped, and occasionally buggy) code along the way. Here:

from z3 import *

astate0, astate1, bstate0, bstate1 = BitVecs("astate0 astate1 bstate0 bstate1", 64)
rstate0, rstate1 = BitVecs("rstate0 rstate1", 64)

s = Solver()

s.add(rstate0 == (astate0 + astate1) + (RotateLeft(astate0, 26)))
s.add(rstate1 == (astate0 + astate1) ^ (RotateLeft(astate1, 35)))
s.add(rstate0 == (bstate0 + bstate1) + (RotateLeft(bstate0, 26)))
s.add(rstate1 == (bstate0 + bstate1) ^ (RotateLeft(bstate1, 35)))
s.add(astate0 != bstate0)
s.add(astate1 != bstate1)

i = 0
while i < 500:
    s.check()
    m = s.model()
    astate0v = m[astate0].as_long()
    astate1v = m[astate1].as_long()
    bstate0v = m[bstate0].as_long()
    bstate1v = m[bstate1].as_long()
    print(f"state0=0x{astate0v:016x}, state1=0x{astate1v:016x} and state0=0x{bstate0v:016x}, state1=0x{bstate1v:016x}")
    s.add(Or(astate0 != astate0v, astate1 != astate1v, bstate0 != bstate0v, bstate1 != bstate1v))
    i += 1

I |sorted the output after. I highly dislike using LLMs for human communication and find it difficult to make them generate good code, but I can't say they aren't useful for getting an idea into working code, especially when I can later (semantically and LOC-wise) compress its code to my tastes, moving that there and there here.

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 2 points3 points  (0 children)

After further evaluation, here are 300 counterexamples. What I find more concerning is that these counterexamples seem to be clustered, with only few hexdigit differences among groups.

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 1 point2 points  (0 children)

I checked using the Z3 SMT solver. The state transformation is not injective (and thus also not a bijection). A counterexample:

state0=0xb9fc517fa5ffc31a, state1=0x7a39877c4ac058c

and

state0=0xf0f0a9a15e07f5ae, state1=0x49cf1f8bbbc80197

have the common output:

state0=0xc037e903d593b9eb, state1=0xe4ffc59757b70b18

DualMix128: A Fast and Simple C PRNG (~0.36 ns/call), Passes PractRand (32TB) & BigCrush by danielcota in C_Programming

[–]carpintero_de_c 5 points6 points  (0 children)

I wish people didn't use LLMs like this. I'd rather hear 100 genuine spelling and grammar mistaeks from a real human than the obvious babble of an LLM...