Skip to content

Instantly share code, notes, and snippets.

@mrbid
Last active October 22, 2022 10:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrbid/51ed2963c88981452a5f87a3b072f8fb to your computer and use it in GitHub Desktop.
Save mrbid/51ed2963c88981452a5f87a3b072f8fb to your computer and use it in GitHub Desktop.
Benchmarking random float functions.
/*
James William Fletcher (github.com/mrbid)
August 2021
Benchmarking random float functions.
https://james-william-fletcher.medium.com/benchmarking-random-float-functions-in-c-13b9febb3d5b
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <locale.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <x86intrin.h>
#pragma GCC diagnostic ignored "-Wunused-result"
#define AVGITER 3000000
#define rand_min -20
#define rand_max 20
// classic random
float rand_float1(const float min, const float max)
{
static const float rmax = (float)RAND_MAX;
return ( ( (((float)rand())+1e-7f) / rmax ) * (max-min) ) + min;
}
float rand_float2(const float min, const float max)
{
static const float FLOAT_UINT64_MAX = (float)UINT64_MAX;
int f = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
uint64_t s = 0;
ssize_t result = read(f, &s, sizeof(uint64_t));
close(f);
return ( ( (((float)s)+1e-7f) / FLOAT_UINT64_MAX ) * (max-min) ) + min;
}
// https://stackoverflow.com/questions/686353/random-float-number-generation
float rand_float3() // normal range 0-1
{
uint_least32_t r = (rand() & 0xffff) + ((rand() & 0x00ff) << 16);
return (float)r * 5.9604645E-8f;
}
float rand_float4() // normal range 0-1
{
uint32_t pattern = 0x3f800000;
uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());
pattern |= random23;
char buffer[sizeof(float)];
memcpy(buffer, &pattern, sizeof(float));
float f;
memcpy(&f, buffer, sizeof(float));
return f - 1.0f;
}
// adapted from ogre3d asm_math.h
// https://www.flipcode.com/archives/07-15-2002.shtml
// https://www.cs.cmu.edu/afs/andrew/scs/cs/oldfiles/15-494-sp09/dst/A/sw/ogre-1.6.4/OgreMain/include/asm_math.h
// https://gist.github.com/mrbid/51ed2963c88981452a5f87a3b072f8fb#file-random_float_bench-c-L59
float rand_float5(const __int64_t seed)
{
static __int64_t q = 8008135;
if(seed != 0)
q = seed;
__m64 mm0 = _mm_cvtsi64_m64(q);
__m64 mm1 = _m_pshufw(mm0, 0x1E);
mm0 = _mm_add_pi32(mm0, mm1);
q = _m_to_int64(mm0);
_m_empty();
return q;
}
static inline float tame(const float input, const float min, const float max)
{
static const float FLOAT_MAX = 9223372036854775807.0f;
return ( ( fabsf(input+1e-7f) / FLOAT_MAX ) * (max-min) ) + min;
}
static inline float scale(const float normal, const float min, const float max)
{
return ( normal * (max-min) ) + min;
}
void secure_random_srand()
{
unsigned int s = 0;
int f = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
read(f, &s, sizeof(unsigned int));
close(f);
srand(s);
}
uint64_t secure_random_seed()
{
uint64_t s = 0;
int f = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
read(f, &s, sizeof(uint64_t));
close(f);
return s;
}
int main()
{
secure_random_srand();
rand_float5(secure_random_seed());
printf("\n");
setlocale(LC_NUMERIC, "");
float ret = 0;
uint64_t st = 0, et = 0, avg = 0;
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += rand_float1(-20, 20);
avg += __rdtsc()-st;
}
printf("rand_float1() Cycles: %'lu\n", avg / AVGITER);
printf("%.20f\n\n", rand_float1(rand_min, rand_max));
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += rand_float2(-20, 20);
avg += __rdtsc()-st;
}
printf("rand_float2() Cycles: %'lu\n", avg / AVGITER);
printf("%.20f\n\n", rand_float2(rand_min, rand_max));
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += rand_float3();
avg += __rdtsc()-st;
}
printf("rand_float3() Cycles: %'lu\n", avg / AVGITER);
printf("%.20f\n\n", scale(rand_float3(), rand_min, rand_max));
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += rand_float4();
avg += __rdtsc()-st;
}
printf("rand_float4() Cycles: %'lu\n", avg / AVGITER);
printf("%.20f\n\n", scale(rand_float4(), rand_min, rand_max));
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += rand_float5(0);
avg += __rdtsc()-st;
}
printf("rand_float5() Cycles: %'lu\n", avg / AVGITER);
printf("%.20f\n\n", tame(rand_float5(0), rand_min, rand_max));
// done
printf("%c\n", (char)ret); // forces the compiler to not disregard the functions we are testing
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment