Randomizer

The Partridge Family were neither partridges nor a family. Discuss.
MrGodin
Posts: 721
Joined: November 30th, 2013, 7:40 pm
Location: Merville, British Columbia Canada

Randomizer

Post by MrGodin » July 14th, 2018, 8:32 pm

Simple random generator

Code: Select all

#pragma once
#include <random>
#include <windows.h>

template<class Gen>
class RandomGenerator
{
	std::random_device rd;
	Gen rng;
public:
	RandomGenerator()
	{
		rng = Gen(rd());
	}

	template<typename T>
	T Get(T min, T max) {}
	template<>
	int Get<int>(int min, int max)
	{
		std::uniform_int_distribution<int> dist(min, max);
		return dist(rng);
	}
	template<>
	double Get<double>(double min, double max)
	{
		std::uniform_real_distribution<double> dist(min, max);
		return dist(rng);
	}
	template<>
	float Get<float>(float min, float max)
	{
		std::uniform_real_distribution<float> dist(min, max);
		return dist(rng);
	}


};

using RandG = RandomGenerator<std::mt19937>;
use like this :
RandG randG;
int result_int = randG.Get<int>(10,20);
double result_double = randG.Get<double>(10.0,20.0);
float result_float = randG.Get<float>(10.0f,20.0f);
Hope you find it useful
Curiosity killed the cat, satisfaction brought him back

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Randomizer

Post by albinopapa » July 15th, 2018, 5:11 am

This should clean things up a bit for ya.

Code: Select all

template<class Gen>
class RandomGenerator
{
	std::random_device rd;
	Gen rng;
	
public:
	RandomGenerator()
	{
		rng = Gen( rd() );
	}
	
	template<typename T>
	std::enable_if_t<std::is_integral_v<T>, T> Get( T min, T max )
	{
		static_assert( sizeof( T ) > 1, "T must be of type short or larger integral type" );

		std::uniform_int_distribution<T> dist( min, max );
		return dist( rng );

	}

	template<typename T>
	std::enable_if_t<std::is_floating_point_v<T>, T> Get( T min, T max )
	{
		std::uniform_real_distribution<T> dist( min, max );
		return dist( rng );
	}

};

using RandG = RandomGenerator<std::mt19937>;
The enable_if_t helps the compiler direct integeral types to the first one, error if passing in a char type and float or double to the second one. Since you should be passing in the values of the type you want returned, you won't need to use template parameters:

Code: Select all

RandG randg;
const float randFloat = randg.Get( 2.5f, 10.9f );
const int randInt = randg.Get( 0, 100 );
const double randDouble = randg.Get( -3.141592, 3.141592 );
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

MrGodin
Posts: 721
Joined: November 30th, 2013, 7:40 pm
Location: Merville, British Columbia Canada

Re: Randomizer

Post by MrGodin » July 15th, 2018, 6:16 am

Nice!, I like that
Curiosity killed the cat, satisfaction brought him back

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Randomizer

Post by albinopapa » July 15th, 2018, 6:30 am

:)
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

freqit
Posts: 15
Joined: February 18th, 2017, 4:47 pm

Re: Randomizer

Post by freqit » July 15th, 2018, 9:54 am

Here is a randomizer I came across while looking for tutorials.

unsigned int f_randi(unsigned int index)
{
index = (index << 13) ^ index;
return ((index * (index * index * 15731 + 789221) + 1376312589) & 0x7fffffff);
}

Source: Eskil Steenberg - https://www.youtube.com/watch?v=443UNeGrFoM&t=3s

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Randomizer

Post by albinopapa » July 15th, 2018, 7:08 pm

Watched about an hour of this video you linked to and I like what the guy is saying, didn't agree with everything he said, but at least he had logical reasons for why he believes that way.

As far as the randomizer you posted, I think MrGodin was just looking for an easier, friendlier way of creating random numbers using the C++ library and not having to create his own randomizing algorithm.

Not that this is the point of the post, I feel I should at least mention a few disagreements I had.
He says languages that hide meanings are bad. The cases he used are macros and C++ specifically function and operator overloading. I'll agree on a few things, I too hate macros, implicit conversions are error prone and hard to debug and operator overloading can be misleading.

Chili uses the operator* in his vector class as the dot product between two vectors and to scale a vector by a scalar. He is explicit about pairwise multiplication ( it's in his 3D Fundamentals tutorials ). He also uses the % for cross product, which to me would be confusing had I not watched the videos.

In general, your overloads should be consistent with what is expected. Since pairwise multiplication of a vector isn't really a mathematical thing overloading the operator* between two vectors probably shouldn't exist.

As for general function overloading, I just find it more of a convenience than anything. Having one function name with different parameters to determine the behavior of the function is so much better. I dabbled a bit in C and coming up with unique names for every function was a pain, especially when they all basically did the same thing with different sets of data.

Long ass names for variables can be a good and bad thing. One of the good things is it is descriptive and explicit. The bad thing is, how to keep your code clean and readable. Now, for most of you that can read really tiny print, GREAT!, your lines can be 100+ characters long and still fit on the screen. For some of us though, we'd have to scroll to the right in order to see what the end of the line looks like which slows production. There is a reason it is generally accepted to try to keep your lines no longer than about 80 characters.

One of the reasons for the complaints_about_long_ass_names especially in C is because the C language doesn't have namespaces. If it did, you could easily have shorter names, still be descriptive and have the same function name without any interference.

As an example, he has a function called: testify_buffer_create();
Now without introducing anything other than namespace ( classes for instance ), see how namespaces can help.

Code: Select all

namespace testify
{
    namespace buffer
    {
        THandle create();
        void*     get( THandle* handle, uint32_t* size );
        void       set( THandle* handle, void* data, uint32_t size );
    }
    namespace network
    {
        uint32_t wait( THandle* handle, boolean* read, boolean* write, ... );
    }
    void type( THandle* handle );
    void free( THandle* handle );    
}

// Usage:
THandle* my_buffer = testify::buffer::create();
In the usage, you would still write out explicity which create function you want to use, but in the setup you get to reduce the name lengths and encapsulate everything involving this one type of buffer within a namespace. It also gives you the "directory like structure" Eskil describes.

Of course, then someone would do something stupid and put a using namespace declaration and you'd lose all the benefits of having namespaces in the first place.

The benefit of having namespaces in C++ is because of function overloading. That way, you can have your DoSomething() function and some third party library can have their DoSomething() function. As long as yours and theirs are in different namespaces, there is no ambiguity between which the compiler should use. Since there are no namespaces in C, the third party library might prefix the name like: sdl_CreateBuffer() and yours might be chili_CreateBuffer().

I for one prefer shorter functions which might call other functions to handle things. I don't agree with his 1,000+ line main render loop. He already uses {} to separate out sections of code, so why not make them separate functions? There are state changes with their own list of things to do, this is when I'd consider making functions that handle those specific states. One of the benefits of creating functions is code reuse yes, but another is limiting the scope of the function so bugs might be easier to find. I can't imagine trying to find and debug that 1,000 line function. Breaking it up into smaller pieces, you'd be able to narrow down where the bug is because you limit where the bug lives. This way you might only have 50 lines to look through.

I've heard a function should fit on a single screen, so you can easily look through it without having to scroll. I would love to agree with this, but as I mentioned earlier, it's all going to depend on eyesight. I have my font size at around 14 with a zoom factor of 100%, so I only get about 26 lines of code on a single screen. I've seen YT videos where either the font is set around 8 or the zoom factor is around 50%. I can't see the code to follow along, and if I were to download the source code, the function would take 2 to 2.5 screen heights, not to mention a couple of screen widths.

I've tried different formatting styles with names and labels, and I really haven't settled on anything as of yet.
class MyClass{};
void AddTwoInts( int _a, int b){ const int c = _a + _b; }
#define MY_MACRO
enum class Color{ Red, Green, Blue };
const auto myColor = Color::Red;
namespace MyNamespace

As you can see, there is some overlap. I try to find ways to avoid naming collisions, without having to come up with completely unique names each time. I also want names to be descriptive, but not extremely long.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

freqit
Posts: 15
Joined: February 18th, 2017, 4:47 pm

Re: Randomizer

Post by freqit » July 16th, 2018, 9:00 am

I'm just a beginner still and can't really comment on why namespace is better or not to use for example vector overloading or other functions as your example. I can see tho how useful it can be if you are using third party code, but did not Eskil talk about how important it is NOT to use third party code in your projects? As this might render your work useless in the future and even give you more work in the end than actually coding what you need instead of a third party library. This is of course on a more professional level. As for me as a hobby programmer I will probally like it when I get there :)

A nice way of breaking down long function names to fit the width, readable and clear.

Code: Select all

#define internal static 

internal void
Win32DisplayBufferInWindow(win32_offscreen_buffer *Buffer,
                           HDC DeviceContext, int WindowWidth, int WindowHeight)
{
    StretchDIBits(DeviceContext,
                  0, 0, WindowWidth, WindowHeight,
                  0, 0, Buffer->Width, Buffer->Height,
                  Buffer->Memory,
                  &Buffer->Info,
                  DIB_RGB_COLORS, SRCCOPY);
}


albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Randomizer

Post by albinopapa » July 16th, 2018, 10:48 am

Well, one thing he did say is he doesn't trust anyone. People drop projects eventually, companies change management or ownership and so on, so the use of third party libraries in that sense can bite you.

You should make your own tools from time to time as it will give you some experience in creating modular code that can be reused for other projects and insight into what goes into making libraries. For third party libraries that are written with the explicit intent to be used by others, they go through testing and continually get bug reports from the community to fix.

One of the benefits to using a third party library is not having to learn everything on your own. SFML for instance, makes it super simple to create a window, render graphics to the window and even create and manage socket connections. All Windows/Linux/etc API calls are encapsulated in SFML classes and the sf namespace. Last I checked they are stuck using C++03 standards/idioms to support the most compilers and code bases, but C++ standards/idioms nonetheless.

In order to avoid using third party libraries, you will need to learn all the things that a third party library would have supplied had you gone that route; creating and managing a window and it's message loop, setting up/initializing the graphics library ( OpenGL, Direct3D, Vulkan, etc ), creating and managing network resources, handling packets, multi-threading and so on.

He's technically not even following his own rules exactly if he even uses any of the C standard library. He surely isn't writing assembly code to make his own printf functions or rewriting his own memory allocators. First party would be code you wrote and third part would be code someone else wrote, so wouldn't the standard library also be a third party library? Yeah, the language has been around for 40+ years, but you can't be an absolutist unless you wrote your own standard library from scratch using ASM or something even closer to the metal, like the code for the processor you are running on.

Yeah, I'm nitpicking here, but it just shows how absurd it is to say "never use third party libraries".

If anything, use the third party libraries on a few projects. While you are learning new things, start replacing it with your own implementations. Heck, the chili framework is third party and he has repeatedly said learn on it then replace with your own. Third party libraries are there to help, not screw you over hopefully. You probably won't have to worry about a company dropping support and leaving you with your pants down. You will have the code on your machine and unless they start requiring licensing fees for the use of their code, you can modify or replace what you need. Not only that, you probably won't be switching libraries mid project anyway, so when the project ends just use another library or write your own from there.

Code: Select all

#define internal static 

internal void
Win32DisplayBufferInWindow(win32_offscreen_buffer *Buffer,
                           HDC DeviceContext, int WindowWidth, int WindowHeight)
{
    StretchDIBits(DeviceContext,
                  0, 0, WindowWidth, WindowHeight,
                  0, 0, Buffer->Width, Buffer->Height,
                  Buffer->Memory,
                  &Buffer->Info,
                  DIB_RGB_COLORS, SRCCOPY);
}
I like the grouping of the StretchDIBits() functionc all, with the exception of DeviceContext being up on the same line as the call to the function:

Code: Select all

// I personally tend to miss the linkage specifier and return type if it's not on the same line as function name.
// Also, if you are going to make the param list vertical, might as well make them all vertical
internal void Win32DisplayBufferInWindow( 
	win32_offscreen_buffer *Buffer,
	HDC DeviceContext, 
	int WindowWidth, 
	int WindowHeight )
{
	// This may seem inconsistent with previous comment, but I can't see putting 0, on their own lines, especially since
	// they contextually are grouped with the width and height params.
	StretchDIBits( 
		DeviceContext,
		0, 0, WindowWidth, WindowHeight,
		0, 0, Buffer->Width, Buffer->Height,
		Buffer->Memory,
		&Buffer->Info,
		DIB_RGB_COLORS, 
		SRCCOPY );
}
Also, spacing is key, which is something else he pointed out. I always put a space after the opening parenthesisand before the closing parenthesis: DoSomethingWith( myVar );

Actually, I have VS setup to do this for me when I type a closing brace } or copy/paste my code.

Don't worry about the details, code how you want, learn your own style and don't let the minutia get in the way. You'll find what works for you and it may not be what others like or agree with. I was on a kick of using Hungarian notation which prefixes member variables with lower case m_, global vars with g_ and the like. Some find it useful to avoid naming collisions so they can reuse the simpler name without the g_ or m_ prefix as a local function variable; const float radius = m_Radius; . Not everyone likes it. Recently, I have started prefixing function parameters with an underscore for the same reason, so I can reuse the simpler name for locals. Others go the other way round, prefixing their member variables with the underscore. I have also tried underscoring long names instead of using camel case, yes it's descriptive but ugly.

int some_really_long_descriptive_name_for_an_int
int someReallyLongDescriptiveNameForAnInt

Ok, neither one looks nice, with the underscore one looking only slightly better. What I realized though by doing it was my variable name length grew larger than needed. I felt more free to describe what the variable was and did in the name instead of just a label for what it was in context.

float dot_product_result_between_light_direction_and_surface_normal = dot_product( light_direction, surface_normal );
float lightIntensity = dot_product( lightDirection, surfaceNormal );

Ok, maybe I didn't really write out something like that, because I'll be damned if I'm going to write that out each time thereafter when I want to use it, but the idea is there, especially if I didn't know a technical name for it like "light intensity" lol.

Just showing that you can be fluid with your coding style until you land on something you really dig. If you do get into a team project, professional or otherwise, it's always a good idea to get everyone on the same page with coding styles. Keeps the project coherent and readable and makes it look like it was written by one person and not hacked together.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Randomizer

Post by albinopapa » July 16th, 2018, 10:49 am

Yet another thread has been hijacked...sorry MrGodin.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

freqit
Posts: 15
Joined: February 18th, 2017, 4:47 pm

Re: Randomizer

Post by freqit » July 16th, 2018, 11:51 am

First off, Sorry Mr Godin for me and albinopapa hijacking your thread, was not intended at all. Possibly to move this? :)

I Agree, of course there are reliable 3rd party libraries that is great, SDL, SFML, Chili, STB and so on, which are great for Learning and also to create top notch software.

Code: Select all

internal void
Win32DisplayBufferInWindow(win32_offscreen_buffer *Buffer,
                           HDC DeviceContext, int WindowWidth, int WindowHeight)
{
}

The reason for me to keep the Win32Display on 2 lines is that it easier and faster to locate the function name instead of doing it vertically as you suggested, and to visually seperate the function name from its "function" (body).

Anyways, I got a long way to go before I can discuss these things proper :)
I'm starting my first c++ course in 2 months, goes on for 6 months.

Post Reply