useful macros

M

Malcolm McLean

I find I use these all the time.

uniform() - generate a random number on 0 - 1.0 minus epsilon
lerp() - linearly interpolate between a and b by t.
clamp() - force x to the range low to high.

Anyone got any more?
 
W

winndy

I find I use these all the time.

uniform() - generate a random number on 0 - 1.0 minus epsilon
lerp() - linearly interpolate between a and b by t.
clamp() - force x to the range low to high.

Anyone got any more?

These macros in which header file on linux?

BR
 
M

Malcolm McLean

בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
These macros in which header file on linux?
I write these macros and put them at the top of pure ANSI source files.

I didn't provide definitions because most regulars could easily write thesemacros in under a minute.
 
B

Ben Bacarisse

Malcolm McLean said:
בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
I write these macros and put them at the top of pure ANSI source files.

I didn't provide definitions because most regulars could easily write
these macros in under a minute.

The first is a little tricky. If you insist on absolute uniformity and
exactly the closed interval [0, 1-DBL_EPSILON], I'd have to work for
more than a minute. If you want only the half-open interval [0, 1) then
there is still a tricky boundary case of wide integers (e.g. 64-bit
ints) to consider.
 
J

James Kuyper

Malcolm McLean said:
בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy: ....
I write these macros and put them at the top of pure ANSI source files.

I didn't provide definitions because most regulars could easily write
these macros in under a minute.

The first is a little tricky. If you insist on absolute uniformity and
exactly the closed interval [0, 1-DBL_EPSILON], I'd have to work for
more than a minute. ...

The wording is ambiguous; it could be interpreted as implying that the
macro takes an argument named 'epsilon'. If so, the result should
probably have the same type as 'epsilon', which would be the only reason
I can come up with why a macro would be more appropriate than a
function. The macro would have to use _Generic().

I suspect you're thinking about a function which can produce every
representable number between 0 and nextafter(1.0, 0.0), with a uniform
probability distribution. I agree, that would take a lot more than one
minute to write up. However, I'd guess he was thinking of something
along the lines of

#define uniform() (rand()/(1.0 + RAND_MAX))

which can produce only RAND_MAX+1 different values, but those values can
be uniformly distributed if RAND_MAX+1 is an integer power of FLT_RADIX
and RAND_MAX*DBL_EPSILON < 1.0, which is often the case.

Note: while 1 + DBL_EPSILON is, by definition, the same as
nextafter(1.0, 2.0), 1 - DBL_EPSILON need not be the same as
nextafter(1.0, 0.0), and usually won't be. The model for the
representation of floating point values described in 5.2.4.2.2 is not
mandatory; it's used solely for exposition of the requirements of that
section. However, if it's a sufficiently accurate description of the
actual representation of a double, then nextafter(1.0, 0.0) should be
1.0-DBL_EPSILON/FLT_RADIX.
 
B

Ben Bacarisse

James Kuyper said:
Malcolm McLean said:
בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
On 5月27æ—¥, 上åˆ4æ—¶08分, Malcolm McLean <[email protected]>
wrote: ...
uniform() - generate a random number on 0 - 1.0 minus epsilon ...
I write these macros and put them at the top of pure ANSI source files.

I didn't provide definitions because most regulars could easily write
these macros in under a minute.

The first is a little tricky. If you insist on absolute uniformity and
exactly the closed interval [0, 1-DBL_EPSILON], I'd have to work for
more than a minute. ...

The wording is ambiguous; it could be interpreted as implying that the
macro takes an argument named 'epsilon'. If so, the result should
probably have the same type as 'epsilon', which would be the only reason
I can come up with why a macro would be more appropriate than a
function. The macro would have to use _Generic().

I suspect you're thinking about a function which can produce every
representable number between 0 and nextafter(1.0, 0.0), with a uniform
probability distribution.

No, I was not thinking of such a complex interpretation. I interpreted
the uniformity to simply apply to some set of distinct values -- not to
every representable value.

My point was simply that insisting on some particular maximum less than
1.0 complicates matters, but, in retrospect, I don't think that is what
Malcolm intended. I think the use of epsilon was probably there just to
indicate that the largest returned value should be strictly less than
1.0.
I agree, that would take a lot more than one
minute to write up. However, I'd guess he was thinking of something
along the lines of

#define uniform() (rand()/(1.0 + RAND_MAX))

which can produce only RAND_MAX+1 different values, but those values can
be uniformly distributed if RAND_MAX+1 is an integer power of FLT_RADIX
and RAND_MAX*DBL_EPSILON < 1.0, which is often the case.

And my second point was that with more and more 64-bit systems, one is
increasingly likely to come across situations where the above macro
might not only produce non-uniform numbers, but where the result can be
equal to 1.0. This can give rise to all sorts of problems (but all with
very low probability, of course).

<snip>
 
B

BartC

James Kuyper said:
On 05/30/2012 11:45 AM, Ben Bacarisse wrote:
The first is a little tricky. If you insist on absolute uniformity and
exactly the closed interval [0, 1-DBL_EPSILON], I'd have to work for
more than a minute. ...
I suspect you're thinking about a function which can produce every
representable number between 0 and nextafter(1.0, 0.0), with a uniform
probability distribution. I agree, that would take a lot more than one
minute to write up. However, I'd guess he was thinking of something
along the lines of

#define uniform() (rand()/(1.0 + RAND_MAX))

which can produce only RAND_MAX+1 different values, but those values can
be uniformly distributed if RAND_MAX+1 is an integer power of FLT_RADIX
and RAND_MAX*DBL_EPSILON < 1.0, which is often the case.

I use a function random(a..b) which returns a random integer from a to b
inclusive (in a scripting language, but it calls C's rand()).

I've just tested this, and over a large number of calls, it seems to produce
a uniform distribution down to 0.001% and better. (And it doesn't know what
RAND_MAX is except that it might be as low as 32767.)

By choosing the range 0 to 999999 for example, then dividing the result by
1000000.0, that ought to produce a linear distribution over 0.000000 to
0.999999. That definition seems quite adequate for many purposes. I don't
know whether you're thinking that there are more numbers between 0.25 and
0.5, than between 0.5 and 1.0 for example, and this somehow needs to be
reflected in this distribution.

In that case a different approach can be used, but I'm not sure how useful
is a random number between 0.0 and 1.0, that most of the time is hovering
near zero.
 
J

James Kuyper

James Kuyper said:
On 05/30/2012 11:45 AM, Ben Bacarisse wrote:
The first is a little tricky. If you insist on absolute uniformity and
exactly the closed interval [0, 1-DBL_EPSILON], I'd have to work for
more than a minute. ...
I suspect you're thinking about a function which can produce every
representable number between 0 and nextafter(1.0, 0.0), with a uniform
probability distribution. I agree, that would take a lot more than one
minute to write up. However, I'd guess he was thinking of something
along the lines of

#define uniform() (rand()/(1.0 + RAND_MAX))

which can produce only RAND_MAX+1 different values, but those values can
be uniformly distributed if RAND_MAX+1 is an integer power of FLT_RADIX
and RAND_MAX*DBL_EPSILON < 1.0, which is often the case.

I use a function random(a..b) which returns a random integer from a to b
inclusive (in a scripting language, but it calls C's rand()).

I've just tested this, and over a large number of calls, it seems to produce
a uniform distribution down to 0.001% and better. (And it doesn't know what
RAND_MAX is except that it might be as low as 32767.)

By choosing the range 0 to 999999 for example, then dividing the result by
1000000.0, that ought to produce a linear distribution over 0.000000 to
0.999999. That definition seems quite adequate for many purposes. I don't
know whether you're thinking that there are more numbers between 0.25 and
0.5, than between 0.5 and 1.0 for example, and this somehow needs to be
reflected in this distribution.

No, that's not usually a problem, because essentially all real-world
implementations of C have a FLT_RADIX which is a power of 2. However, on
any system where FLT_RADIX is not an integer multiple of 5, the number
of representable floating point values between 0.5 and 0.6 IS different
(usually by 1) from the number of representable values between 0.6 and
0.7. On such a system, (0.6 - 0.5) != (0.7 - 0.6). These differences are
small, and don't matter for most purposes, but in some contexts they can
have an affect that can be measured. The distribution is exactly uniform
only when there are no such differences.

More important for many purposes is the fact that you can generate only
RAND_MAX different floating point values that way. That can be quite
acceptable for many purposes, and completely unacceptable for others.
Between each consecutive pair of values that can be generated there's a
gap containing huge numbers of representable floating point values that
can never be generated. The gaps all have exactly the same size and are
all in phase with each other, which means they can have very noticeable
effects on certain kinds of numerical simulations, particularly in
Fourier analysis.
 
B

BartC

James Kuyper said:
On 05/30/2012 06:24 PM, BartC wrote:

(Between 0.25/0.5 and 0.5/1.0 probably the same; I meant within two equal
intervals.)
More important for many purposes is the fact that you can generate only
RAND_MAX different floating point values that way. That can be quite
acceptable for many purposes, and completely unacceptable for others.

Minor problem. I actually use two successive calls to rand() to give me a
bigger range. And for more serious purposes, a better RNG can be plugged in
(G. Marsaglia has posted a few complicated ones here).
Between each consecutive pair of values that can be generated there's a
gap containing huge numbers of representable floating point values that
can never be generated. The gaps all have exactly the same size and are
all in phase with each other, which means they can have very noticeable
effects on certain kinds of numerical simulations, particularly in
Fourier analysis.

People seem to take random numbers very seriously when the subject comes up.
If it's that critical (or money is at stake), then someone would use a
specialist function or take time to put something together just right. They
wouldn't trust a throwaway macro to do the job.

(I used to do 'wallpaper' tests with early random number generators of my
own. The more interesting the patterns that were generated, the less use
they were for producing random numbers. Yet even then, they could be
surprisingly useful. Sometimes, RNGs just don't need to be that good.)
 
K

Keith Thompson

BartC said:
I use a function random(a..b) which returns a random integer from a to b
inclusive (in a scripting language, but it calls C's rand()).

I've just tested this, and over a large number of calls, it seems to produce
a uniform distribution down to 0.001% and better. (And it doesn't know what
RAND_MAX is except that it might be as low as 32767.)
[...]

Does it perform multiple calls to rand() in some cases?

If not, it's not possible to get a completely uniform distribution, a
problem that might be difficult to see on a system with, say, RAND_MAX
== 2147483647.

For example, if RAND_MAX==32767, then there are exactly 32768 equally
likely results from rand(). random(0..30000), if it depends on a single
call to rand(), will return some results twice as often as others;
random(0..40000) cannot return all possible results.

Question 13.16 of the comp.lang.c FAQ covers this.
 
B

BartC

Keith Thompson said:
BartC said:
I use a function random(a..b) which returns a random integer from a to b
inclusive (in a scripting language, but it calls C's rand()).

I've just tested this, and over a large number of calls, it seems to
produce
a uniform distribution down to 0.001% and better. (And it doesn't know
what
RAND_MAX is except that it might be as low as 32767.)
[...]

Does it perform multiple calls to rand() in some cases?

Yes (two calls each time). Just to guarantee enough bits to play with. The
distribution might not be ideal, but it works reasonably well and it's easy
enough to add some variability if needed.
If not, it's not possible to get a completely uniform distribution, a
problem that might be difficult to see on a system with, say, RAND_MAX
== 2147483647.

For example, if RAND_MAX==32767, then there are exactly 32768 equally
likely results from rand(). random(0..30000), if it depends on a single
call to rand(), will return some results twice as often as others;
random(0..40000) cannot return all possible results.

Yes; the basic calculation, for a range of a..b, is rand()%(b-a+1)+a. Since
it uses a remainder operation, you might expect some results to appear more
often than others, and this test shows that:

#include <stdio.h>
#include <stdlib.h>

int main(void){
#define M 100000000
#define N 30000
int counts[N]={0};
int i,j,k,r;

for (k=1; k<=M; ++k) {
r=rand();
++counts[r%N];
}

for (i=0; i<15; ++i)
printf("%d: %d Dev: %d\n",i,counts, counts-(M/N));

puts("...");

for (i=N-15; i<N; ++i)
printf("%d: %d Dev: %d\n",i,counts, counts-(M/N));
}

But change the r=rand() line to r=rand()<<15 | rand(), and deviation on each
count is far more variable. So it's just necessary to make sure the a..b
range is much smaller than the range of the rand() function. And quite often
you will only need a narrow range.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,186
Latest member
vinaykumar_nevatia

Latest Threads

Top