aboutsummaryrefslogtreecommitdiffstats
path: root/random_float.c
blob: b4b6557538e652a383179fe51798f6cdbda55da1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST

#include <math.h>


long double
libsimple_random_float(uintmax_t (*rng)(size_t bits, void *user), void *user, long double min, long double postmax) /* TODO add test */
{
	long double range, offset, mantissa, value;
	uintmax_t r;
	int exp;
	size_t bits;

	if (min < postmax) {
		range = postmax - min;
		offset = min;
	} else if (min > postmax) {
		range = min - postmax;
		offset = postmax;
	} else {
		return min;
	}

	mantissa = frexpl(range, &exp);
	do {
		bits = sizeof(uintmax_t) * CHAR_BIT;
		r = (*rng)(bits, user);
		while (bits && (r & 1)) {
			exp -= 1;
			bits -= 1;
			r >>= 1;
		}
	} while (!bits);

	bits = sizeof(uintmax_t) * CHAR_BIT;
	r = (*rng)(bits, user);
	value = (long double)r;
	value = fmal(value, 0.5, 0.5);
	value = ldexpl(value, -(int)bits);

	value = ldexpl(value, exp);
	value *= mantissa;
	return value + offset;
}


#else
#include "test.h"

int
main(void)
{
	return 0;
}

#endif