Simplified SDL random function names and added thread-safe versions

This commit is contained in:
Sam Lantinga 2024-06-23 12:11:33 -07:00
parent d013ac80ef
commit 96f2f23240
12 changed files with 167 additions and 90 deletions

View file

@ -1273,46 +1273,19 @@ extern SDL_DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STR
* *
* \since This function is available since SDL 3.0.0. * \since This function is available since SDL 3.0.0.
* *
* \sa SDL_rand_n * \sa SDL_rand
* \sa SDL_rand_float * \sa SDL_randf
* \sa SDL_rand_bits
*/ */
extern SDL_DECLSPEC void SDLCALL SDL_srand(Uint64 seed); extern SDL_DECLSPEC void SDLCALL SDL_srand(Uint64 seed);
/** /**
* Generates 32 pseudo-random bits. * Generate a pseudo-random number less than n for positive n
*
* You likely want to use SDL_rand_n() to get a psuedo-randum number instead.
*
* If you want reproducible output, be sure to initialize with SDL_srand()
* first.
*
* There are no guarantees as to the quality of the random sequence produced,
* and this should not be used for security (cryptography, passwords) or where
* money is on the line (loot-boxes, casinos). There are many random number
* libraries available with different characteristics and you should pick one
* of those to meet any serious needs.
*
* \returns a random value in the range of [0-SDL_MAX_UINT32].
*
* \threadsafety All calls should be made from a single thread
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_srand
* \sa SDL_rand_n
* \sa SDL_rand_float
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_rand_bits(void);
/**
* Generates a pseudo-random number less than n for positive n
* *
* The method used is faster and of better quality than `rand() % n`. Odds are * The method used is faster and of better quality than `rand() % n`. Odds are
* roughly 99.9% even for n = 1 million. Evenness is better for smaller n, and * roughly 99.9% even for n = 1 million. Evenness is better for smaller n, and
* much worse as n gets bigger. * much worse as n gets bigger.
* *
* Example: to simulate a d6 use `SDL_rand_n(6) + 1` The +1 converts 0..5 to * Example: to simulate a d6 use `SDL_rand(6) + 1` The +1 converts 0..5 to
* 1..6 * 1..6
* *
* If you want reproducible output, be sure to initialize with SDL_srand() * If you want reproducible output, be sure to initialize with SDL_srand()
@ -1332,12 +1305,12 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_rand_bits(void);
* \since This function is available since SDL 3.0.0. * \since This function is available since SDL 3.0.0.
* *
* \sa SDL_srand * \sa SDL_srand
* \sa SDL_rand_float * \sa SDL_randf
*/ */
extern SDL_DECLSPEC Sint32 SDLCALL SDL_rand_n(Sint32 n); extern SDL_DECLSPEC Sint32 SDLCALL SDL_rand(Sint32 n);
/** /**
* Generates a uniform pseudo-random floating point number less than 1.0 * Generate a uniform pseudo-random floating point number less than 1.0
* *
* If you want reproducible output, be sure to initialize with SDL_srand() * If you want reproducible output, be sure to initialize with SDL_srand()
* first. * first.
@ -1355,9 +1328,88 @@ extern SDL_DECLSPEC Sint32 SDLCALL SDL_rand_n(Sint32 n);
* \since This function is available since SDL 3.0.0. * \since This function is available since SDL 3.0.0.
* *
* \sa SDL_srand * \sa SDL_srand
* \sa SDL_rand_n * \sa SDL_rand
*/ */
extern SDL_DECLSPEC float SDLCALL SDL_rand_float(void); extern SDL_DECLSPEC float SDLCALL SDL_randf(void);
/**
* Generate a pseudo-random number less than n for positive n
*
* The method used is faster and of better quality than `rand() % n`. Odds are
* roughly 99.9% even for n = 1 million. Evenness is better for smaller n, and
* much worse as n gets bigger.
*
* Example: to simulate a d6 use `SDL_rand_r(state, 6) + 1` The +1 converts 0..5 to
* 1..6
*
* There are no guarantees as to the quality of the random sequence produced,
* and this should not be used for security (cryptography, passwords) or where
* money is on the line (loot-boxes, casinos). There are many random number
* libraries available with different characteristics and you should pick one
* of those to meet any serious needs.
*
* \param state a pointer to the current random number state, this may not be NULL.
* \param n the number of possible outcomes. n must be positive.
* \returns a random value in the range of [0 .. n-1].
*
* \threadsafety This function is thread-safe, as long as the state pointer isn't shared between threads.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_rand
* \sa SDL_rand_bits_r
* \sa SDL_randf_r
*/
extern SDL_DECLSPEC Sint32 SDLCALL SDL_rand_r(Uint64 *state, Sint32 n);
/**
* Generate a uniform pseudo-random floating point number less than 1.0
*
* If you want reproducible output, be sure to initialize with SDL_srand()
* first.
*
* There are no guarantees as to the quality of the random sequence produced,
* and this should not be used for security (cryptography, passwords) or where
* money is on the line (loot-boxes, casinos). There are many random number
* libraries available with different characteristics and you should pick one
* of those to meet any serious needs.
*
* \param state a pointer to the current random number state, this may not be NULL.
* \returns a random value in the range of [0.0, 1.0).
*
* \threadsafety This function is thread-safe, as long as the state pointer isn't shared between threads.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_rand_bits_r
* \sa SDL_rand_r
* \sa SDL_randf
*/
extern SDL_DECLSPEC float SDLCALL SDL_randf_r(Uint64 *state);
/**
* Generate 32 pseudo-random bits.
*
* You likely want to use SDL_rand_r() to get a psuedo-randum number instead.
*
* There are no guarantees as to the quality of the random sequence produced,
* and this should not be used for security (cryptography, passwords) or where
* money is on the line (loot-boxes, casinos). There are many random number
* libraries available with different characteristics and you should pick one
* of those to meet any serious needs.
*
* \param state a pointer to the current random number state, this may not be NULL.
* \returns a random value in the range of [0-SDL_MAX_UINT32].
*
* \threadsafety This function is thread-safe, as long as the state pointer isn't shared between threads.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_rand_r
* \sa SDL_randf_r
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_rand_bits_r(Uint64 *state);
#ifndef SDL_PI_D #ifndef SDL_PI_D
#define SDL_PI_D 3.141592653589793238462643383279502884 /**< pi (double) */ #define SDL_PI_D 3.141592653589793238462643383279502884 /**< pi (double) */

View file

@ -961,9 +961,11 @@ SDL3_0.0.0 {
SDL_powf; SDL_powf;
SDL_qsort; SDL_qsort;
SDL_qsort_r; SDL_qsort_r;
SDL_rand_bits; SDL_rand;
SDL_rand_float; SDL_rand_bits_r;
SDL_rand_n; SDL_rand_r;
SDL_randf;
SDL_randf_r;
SDL_realloc; SDL_realloc;
SDL_round; SDL_round;
SDL_roundf; SDL_roundf;

View file

@ -986,9 +986,11 @@
#define SDL_powf SDL_powf_REAL #define SDL_powf SDL_powf_REAL
#define SDL_qsort SDL_qsort_REAL #define SDL_qsort SDL_qsort_REAL
#define SDL_qsort_r SDL_qsort_r_REAL #define SDL_qsort_r SDL_qsort_r_REAL
#define SDL_rand_bits SDL_rand_bits_REAL #define SDL_rand SDL_rand_REAL
#define SDL_rand_float SDL_rand_float_REAL #define SDL_rand_bits_r SDL_rand_bits_r_REAL
#define SDL_rand_n SDL_rand_n_REAL #define SDL_rand_r SDL_rand_r_REAL
#define SDL_randf SDL_randf_REAL
#define SDL_randf_r SDL_randf_r_REAL
#define SDL_realloc SDL_realloc_REAL #define SDL_realloc SDL_realloc_REAL
#define SDL_round SDL_round_REAL #define SDL_round SDL_round_REAL
#define SDL_roundf SDL_roundf_REAL #define SDL_roundf SDL_roundf_REAL

View file

@ -995,9 +995,11 @@ SDL_DYNAPI_PROC(double,SDL_pow,(double a, double b),(a,b),return)
SDL_DYNAPI_PROC(float,SDL_powf,(float a, float b),(a,b),return) SDL_DYNAPI_PROC(float,SDL_powf,(float a, float b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_qsort,(void *a, size_t b, size_t c, SDL_CompareCallback d),(a,b,c,d),) SDL_DYNAPI_PROC(void,SDL_qsort,(void *a, size_t b, size_t c, SDL_CompareCallback d),(a,b,c,d),)
SDL_DYNAPI_PROC(void,SDL_qsort_r,(void *a, size_t b, size_t c, SDL_CompareCallback_r d, void *e),(a,b,c,d,e),) SDL_DYNAPI_PROC(void,SDL_qsort_r,(void *a, size_t b, size_t c, SDL_CompareCallback_r d, void *e),(a,b,c,d,e),)
SDL_DYNAPI_PROC(Uint32,SDL_rand_bits,(void),(),return) SDL_DYNAPI_PROC(Sint32,SDL_rand,(Sint32 a),(a),return)
SDL_DYNAPI_PROC(float,SDL_rand_float,(void),(),return) SDL_DYNAPI_PROC(Uint32,SDL_rand_bits_r,(Uint64 *a),(a),return)
SDL_DYNAPI_PROC(Sint32,SDL_rand_n,(Sint32 a),(a),return) SDL_DYNAPI_PROC(Sint32,SDL_rand_r,(Uint64 *a, Sint32 b),(a,b),return)
SDL_DYNAPI_PROC(float,SDL_randf,(void),(),return)
SDL_DYNAPI_PROC(float,SDL_randf_r,(Uint64 *a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_realloc,(void *a, size_t b),(a,b),return) SDL_DYNAPI_PROC(void*,SDL_realloc,(void *a, size_t b),(a,b),return)
SDL_DYNAPI_PROC(double,SDL_round,(double a),(a),return) SDL_DYNAPI_PROC(double,SDL_round,(double a),(a),return)
SDL_DYNAPI_PROC(float,SDL_roundf,(float a),(a),return) SDL_DYNAPI_PROC(float,SDL_roundf,(float a),(a),return)

View file

@ -34,12 +34,30 @@ void SDL_srand(Uint64 seed)
SDL_rand_initialized = SDL_TRUE; SDL_rand_initialized = SDL_TRUE;
} }
Uint32 SDL_rand_bits(void) Sint32 SDL_rand(Sint32 n)
{ {
if (!SDL_rand_initialized) { if (!SDL_rand_initialized) {
SDL_srand(0); SDL_srand(0);
} }
return SDL_rand_r(&SDL_rand_state, n);
}
float SDL_randf(void)
{
if (!SDL_rand_initialized) {
SDL_srand(0);
}
return SDL_randf_r(&SDL_rand_state);
}
Uint32 SDL_rand_bits_r(Uint64 *state)
{
if (!state) {
return 0;
}
// The C and A parameters of this LCG have been chosen based on hundreds // The C and A parameters of this LCG have been chosen based on hundreds
// of core-hours of testing with PractRand and TestU01's Crush. // of core-hours of testing with PractRand and TestU01's Crush.
// Using a 32-bit A improves performance on 32-bit architectures. // Using a 32-bit A improves performance on 32-bit architectures.
@ -55,13 +73,13 @@ Uint32 SDL_rand_bits(void)
// Softw Pract Exper. 2022;52(2):443-458. doi: 10.1002/spe.3030 // Softw Pract Exper. 2022;52(2):443-458. doi: 10.1002/spe.3030
// https://arxiv.org/abs/2001.05304v2 // https://arxiv.org/abs/2001.05304v2
SDL_rand_state = SDL_rand_state * 0xff1cd035ul + 0x05; *state = *state * 0xff1cd035ul + 0x05;
// Only return top 32 bits because they have a longer period // Only return top 32 bits because they have a longer period
return (Uint32)(SDL_rand_state >> 32); return (Uint32)(*state >> 32);
} }
Sint32 SDL_rand_n(Sint32 n) Sint32 SDL_rand_r(Uint64 *state, Sint32 n)
{ {
// Algorithm: get 32 bits from SDL_rand_bits() and treat it as a 0.32 bit // Algorithm: get 32 bits from SDL_rand_bits() and treat it as a 0.32 bit
// fixed point number. Multiply by the 31.0 bit n to get a 31.32 bit // fixed point number. Multiply by the 31.0 bit n to get a 31.32 bit
@ -70,18 +88,19 @@ Sint32 SDL_rand_n(Sint32 n)
if (n < 0) { if (n < 0) {
// The algorithm looks like it works for numbers < 0 but it has an // The algorithm looks like it works for numbers < 0 but it has an
// infintesimal chance of returning a value out of range. // infintesimal chance of returning a value out of range.
// Returning -SDL_rand_n(abs(n)) blows up at INT_MIN instead. // Returning -SDL_rand(abs(n)) blows up at INT_MIN instead.
// It's easier to just say no. // It's easier to just say no.
return 0; return 0;
} }
// On 32-bit arch, the compiler will optimize to a single 32-bit multiply // On 32-bit arch, the compiler will optimize to a single 32-bit multiply
Uint64 val = (Uint64)SDL_rand_bits() * n; Uint64 val = (Uint64)SDL_rand_bits_r(state) * n;
return (Sint32)(val >> 32); return (Sint32)(val >> 32);
} }
float SDL_rand_float(void) float SDL_randf_r(Uint64 *state)
{ {
// Note: its using 24 bits because float has 23 bits significand + 1 implicit bit // Note: its using 24 bits because float has 23 bits significand + 1 implicit bit
return (SDL_rand_bits() >> (32 - 24)) * 0x1p-24f; return (SDL_rand_bits_r(state) >> (32 - 24)) * 0x1p-24f;
} }

View file

@ -231,7 +231,7 @@ static int SDLCALL ping_thread(void *ptr)
sdlevent.type = SDL_EVENT_KEY_DOWN; sdlevent.type = SDL_EVENT_KEY_DOWN;
sdlevent.key.key = SDLK_1; sdlevent.key.key = SDLK_1;
SDL_PushEvent(&sdlevent); SDL_PushEvent(&sdlevent);
SDL_Delay(1000 + SDL_rand_n(1000)); SDL_Delay(1000 + SDL_rand(1000));
} }
return cnt; return cnt;
} }

View file

@ -72,8 +72,8 @@ static void DrawPoints(SDL_Renderer *renderer)
SDL_SetRenderDrawColor(renderer, 255, (Uint8)current_color, SDL_SetRenderDrawColor(renderer, 255, (Uint8)current_color,
(Uint8)current_color, (Uint8)current_alpha); (Uint8)current_color, (Uint8)current_alpha);
x = (float)SDL_rand_n(viewport.w); x = (float)SDL_rand(viewport.w);
y = (float)SDL_rand_n(viewport.h); y = (float)SDL_rand(viewport.h);
SDL_RenderPoint(renderer, x, y); SDL_RenderPoint(renderer, x, y);
} }
} }
@ -120,10 +120,10 @@ static void DrawLines(SDL_Renderer *renderer)
SDL_RenderLine(renderer, 0.0f, (float)(viewport.h / 2), (float)(viewport.w - 1), (float)(viewport.h / 2)); SDL_RenderLine(renderer, 0.0f, (float)(viewport.h / 2), (float)(viewport.w - 1), (float)(viewport.h / 2));
SDL_RenderLine(renderer, (float)(viewport.w / 2), 0.0f, (float)(viewport.w / 2), (float)(viewport.h - 1)); SDL_RenderLine(renderer, (float)(viewport.w / 2), 0.0f, (float)(viewport.w / 2), (float)(viewport.h - 1));
} else { } else {
x1 = (float)(SDL_rand_n(viewport.w * 2) - viewport.w); x1 = (float)(SDL_rand(viewport.w * 2) - viewport.w);
x2 = (float)(SDL_rand_n(viewport.w * 2) - viewport.w); x2 = (float)(SDL_rand(viewport.w * 2) - viewport.w);
y1 = (float)(SDL_rand_n(viewport.h * 2) - viewport.h); y1 = (float)(SDL_rand(viewport.h * 2) - viewport.h);
y2 = (float)(SDL_rand_n(viewport.h * 2) - viewport.h); y2 = (float)(SDL_rand(viewport.h * 2) - viewport.h);
SDL_RenderLine(renderer, x1, y1, x2, y2); SDL_RenderLine(renderer, x1, y1, x2, y2);
} }
} }
@ -165,10 +165,10 @@ static void DrawRects(SDL_Renderer *renderer)
SDL_SetRenderDrawColor(renderer, 255, (Uint8)current_color, SDL_SetRenderDrawColor(renderer, 255, (Uint8)current_color,
(Uint8)current_color, (Uint8)current_alpha); (Uint8)current_color, (Uint8)current_alpha);
rect.w = (float)SDL_rand_n(viewport.h / 2); rect.w = (float)SDL_rand(viewport.h / 2);
rect.h = (float)SDL_rand_n(viewport.h / 2); rect.h = (float)SDL_rand(viewport.h / 2);
rect.x = (float)((SDL_rand_n(viewport.w * 2) - viewport.w) - (rect.w / 2)); rect.x = (float)((SDL_rand(viewport.w * 2) - viewport.w) - (rect.w / 2));
rect.y = (float)((SDL_rand_n(viewport.h * 2) - viewport.h) - (rect.h / 2)); rect.y = (float)((SDL_rand(viewport.h * 2) - viewport.h) - (rect.h / 2));
SDL_RenderFillRect(renderer, &rect); SDL_RenderFillRect(renderer, &rect);
} }
} }

View file

@ -1485,15 +1485,15 @@ int main(int argc, char *argv[])
SDL_Rect viewport; SDL_Rect viewport;
SDL_GetRenderViewport(renderer, &viewport); SDL_GetRenderViewport(renderer, &viewport);
for (i = 0; i < num_sprites; ++i) { for (i = 0; i < num_sprites; ++i) {
positions[i].x = (float)SDL_rand_n(viewport.w - sprite_w); positions[i].x = (float)SDL_rand(viewport.w - sprite_w);
positions[i].y = (float)SDL_rand_n(viewport.h - sprite_h); positions[i].y = (float)SDL_rand(viewport.h - sprite_h);
positions[i].w = (float)sprite_w; positions[i].w = (float)sprite_w;
positions[i].h = (float)sprite_h; positions[i].h = (float)sprite_h;
velocities[i].x = 0.0f; velocities[i].x = 0.0f;
velocities[i].y = 0.0f; velocities[i].y = 0.0f;
while (velocities[i].x == 0.f || velocities[i].y == 0.f) { while (velocities[i].x == 0.f || velocities[i].y == 0.f) {
velocities[i].x = (float)(SDL_rand_n(2 + 1) - 1); velocities[i].x = (float)(SDL_rand(2 + 1) - 1);
velocities[i].y = (float)(SDL_rand_n(2 + 1) - 1); velocities[i].y = (float)(SDL_rand(2 + 1) - 1);
} }
} }

View file

@ -74,8 +74,8 @@ static void DrawPoints(SDL_Renderer *renderer)
SDL_SetRenderDrawColor(renderer, 255, (Uint8)current_color, SDL_SetRenderDrawColor(renderer, 255, (Uint8)current_color,
(Uint8)current_color, (Uint8)current_alpha); (Uint8)current_color, (Uint8)current_alpha);
x = (float)SDL_rand_n(viewport.w); x = (float)SDL_rand(viewport.w);
y = (float)SDL_rand_n(viewport.h); y = (float)SDL_rand(viewport.h);
SDL_RenderPoint(renderer, x, y); SDL_RenderPoint(renderer, x, y);
} }
} }
@ -231,20 +231,20 @@ static void loop(void *arg)
break; break;
case SDLK_l: case SDLK_l:
add_line( add_line(
(float)SDL_rand_n(640), (float)SDL_rand(640),
(float)SDL_rand_n(480), (float)SDL_rand(480),
(float)SDL_rand_n(640), (float)SDL_rand(640),
(float)SDL_rand_n(480)); (float)SDL_rand(480));
break; break;
case SDLK_R: case SDLK_R:
num_rects = 0; num_rects = 0;
break; break;
case SDLK_r: case SDLK_r:
add_rect( add_rect(
(float)SDL_rand_n(640), (float)SDL_rand(640),
(float)SDL_rand_n(480), (float)SDL_rand(480),
(float)SDL_rand_n(640), (float)SDL_rand(640),
(float)SDL_rand_n(480)); (float)SDL_rand(480));
break; break;
default: default:
break; break;

View file

@ -189,15 +189,15 @@ int main(int argc, char *argv[])
quit(2); quit(2);
} }
for (i = 0; i < NUM_SPRITES; ++i) { for (i = 0; i < NUM_SPRITES; ++i) {
positions[i].x = (float)(SDL_rand_n(window_w - (int)sprite_w)); positions[i].x = (float)(SDL_rand(window_w - (int)sprite_w));
positions[i].y = (float)(SDL_rand_n(window_h - (int)sprite_h)); positions[i].y = (float)(SDL_rand(window_h - (int)sprite_h));
positions[i].w = sprite_w; positions[i].w = sprite_w;
positions[i].h = sprite_h; positions[i].h = sprite_h;
velocities[i].x = 0.0f; velocities[i].x = 0.0f;
velocities[i].y = 0.0f; velocities[i].y = 0.0f;
while (velocities[i].x == 0.f && velocities[i].y == 0.f) { while (velocities[i].x == 0.f && velocities[i].y == 0.f) {
velocities[i].x = (float)(SDL_rand_n(MAX_SPEED * 2 + 1) - MAX_SPEED); velocities[i].x = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
velocities[i].y = (float)(SDL_rand_n(MAX_SPEED * 2 + 1) - MAX_SPEED); velocities[i].y = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
} }
} }

View file

@ -135,15 +135,15 @@ int main(int argc, char *argv[])
/* Initialize the sprite positions */ /* Initialize the sprite positions */
for (i = 0; i < NUM_SPRITES; ++i) { for (i = 0; i < NUM_SPRITES; ++i) {
positions[i].x = (float)SDL_rand_n(WINDOW_WIDTH - sprite_w); positions[i].x = (float)SDL_rand(WINDOW_WIDTH - sprite_w);
positions[i].y = (float)SDL_rand_n(WINDOW_HEIGHT - sprite_h); positions[i].y = (float)SDL_rand(WINDOW_HEIGHT - sprite_h);
positions[i].w = (float)sprite_w; positions[i].w = (float)sprite_w;
positions[i].h = (float)sprite_h; positions[i].h = (float)sprite_h;
velocities[i].x = 0.0f; velocities[i].x = 0.0f;
velocities[i].y = 0.0f; velocities[i].y = 0.0f;
while (velocities[i].x == 0.f && velocities[i].y == 0.f) { while (velocities[i].x == 0.f && velocities[i].y == 0.f) {
velocities[i].x = (float)(SDL_rand_n(MAX_SPEED * 2 + 1) - MAX_SPEED); velocities[i].x = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
velocities[i].y = (float)(SDL_rand_n(MAX_SPEED * 2 + 1) - MAX_SPEED); velocities[i].y = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
} }
} }

View file

@ -97,15 +97,15 @@ static int InitSprites(void)
} }
for (int i = 0; i < NUM_SPRITES; ++i) { for (int i = 0; i < NUM_SPRITES; ++i) {
positions[i].x = (float)SDL_rand_n(WINDOW_WIDTH - sprite_w); positions[i].x = (float)SDL_rand(WINDOW_WIDTH - sprite_w);
positions[i].y = (float)SDL_rand_n(WINDOW_HEIGHT - sprite_h); positions[i].y = (float)SDL_rand(WINDOW_HEIGHT - sprite_h);
positions[i].w = (float)sprite_w; positions[i].w = (float)sprite_w;
positions[i].h = (float)sprite_h; positions[i].h = (float)sprite_h;
velocities[i].x = 0.0f; velocities[i].x = 0.0f;
velocities[i].y = 0.0f; velocities[i].y = 0.0f;
while (velocities[i].x == 0.f && velocities[i].y == 0.f) { while (velocities[i].x == 0.f && velocities[i].y == 0.f) {
velocities[i].x = (float)(SDL_rand_n(MAX_SPEED * 2 + 1) - MAX_SPEED); velocities[i].x = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
velocities[i].y = (float)(SDL_rand_n(MAX_SPEED * 2 + 1) - MAX_SPEED); velocities[i].y = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
} }
} }