# Algorithm of trand() in SC_RGen.h file

Hello.

I am so curious about the principle of the trand() code.

It looks like the trand() is using base function of other various random functions on the same file.(SC_RGen.h)

Am I never going to understand this kind of random functions algorithm? T T

Have a good year-end.

``````(in SC_RGen.h)

inline uint32 trand(uint32& s1, uint32& s2, uint32& s3) {
s1 = ((s1 & (uint32)-2) << 12) ^ (((s1 << 13) ^ s1) >> 19);
s2 = ((s2 & (uint32)-8) << 4) ^ (((s2 << 2) ^ s2) >> 25);
s3 = ((s3 & (uint32)-16) << 17) ^ (((s3 << 3) ^ s3) >> 11);
return s1 ^ s2 ^ s3;
}
``````

It just does a bunch of random bitwise operations on the numbers 4 seeds, mutating them each time. This code is designed to mimic randomness, it doesn’t need to be perfect, just fast. There really isn’t much point in trying to understand it, unless you specifically want to know how to write random functions, or.perhaps hashing functions. Why did you choose this function?

Because trand() is used multiple times in other random functions, I choose this function.
Yes, I am curious how to make a random function. But I’m not sure where to start looking in that code.

``````    s1 = ((s1 & (uint32)-2) << 12) ^ (((s1 << 13) ^ s1) >> 19);
``````

On this line, do these numbers (-2, 12, 13, 19) have any special meaning? Or are they just choosed randomly? And What is the range of the result of this function?

Thanks!

The range is the entire range of the uint32 - so `2.pow(32)`.

Do the number have any special meaning? No, the entire function is chosen because it gives a good enough approximation of randomness and is fast. That being said, you would interpret the numbers, not as values, but as binary bits. There are some tactics employed in these types of function to help generate randomness, but they are not a property of randomness, but of the binary representation, also, bitshift operations are used because computers can calculate these cheaply, in shader code you will normally see the dot product used as that cheap to compute on a gpu.

This isn’t equal to minus 2, as its an unsigned int, but `2.pow(32) - 3 `

If you understand what all the operators do, then you already understand what the algorithm does, its just a cheap to compute complex mess that makes something that looks random. This sort of makes sense, it is a random function after all!

You can find many examples of these in graphic shader code, heres a nice stackoverflow post on the topic: shader - Random / noise functions for GLSL - Stack Overflow

Honestly, I think spending too much time on this is a waste, there are people out there who have spent years bench-marking many different combinations trying to find the fastest whilst also sufficiently uniform function. There are many other aspects of DSP code that would be worth spending time to study instead.

2 Likes

Thank you, thank you so much.

I am looking around some SuperCollider source code recently, mostly it looks complicate but fun to understand even it is a tiny thing.

Have a good weekend!

I’d be a little weary of this if you aren’t super familiar with c++. The issue is that supercollider was started in the later 90s, early 2000s and c++ basically became a different language in 2011. Reading and learning C++ is a lot like archeology.

As a result there are a lot of bad practices in the code. There has been an effort change this, but refactoring legacy code is hard! If I where you, I’d close by eyes every time you see something in all caps (it’s a macro, particularly the silly LOOP thing), and raw pointers (the us government actually recommends against using c++ because of issue with raw pointers - to simplify somewhat…).

Whilst reading the code base is really good and you should definitely do it(!), don’t use it as an example of how to write good, safe, fast C++ code in 2022.

1 Like As you advised, I will continue to do it slowly.