Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #21379 > unrolled thread

useful macros

Started byMalcolm McLean <malcolm.mclean5@btinternet.com>
First post2012-05-26 13:08 -0700
Last post2012-05-31 10:29 +0100
Articles 11 — 6 participants

Back to article view | Back to comp.lang.c


Contents

  useful macros Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-05-26 13:08 -0700
    Re: useful macros winndy <jiaoyk@gmail.com> - 2012-05-29 20:26 -0700
      Re: useful macros Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-05-30 00:47 -0700
        Re: useful macros Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-05-30 16:45 +0100
          Re: useful macros James Kuyper <jameskuyper@verizon.net> - 2012-05-30 13:10 -0400
            Re: useful macros Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-05-30 21:54 +0100
            Re: useful macros "BartC" <bc@freeuk.com> - 2012-05-30 23:24 +0100
              Re: useful macros James Kuyper <jameskuyper@verizon.net> - 2012-05-30 18:55 -0400
                Re: useful macros "BartC" <bc@freeuk.com> - 2012-05-31 00:45 +0100
              Re: useful macros Keith Thompson <kst-u@mib.org> - 2012-05-30 17:53 -0700
                Re: useful macros "BartC" <bc@freeuk.com> - 2012-05-31 10:29 +0100

#21379 — useful macros

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2012-05-26 13:08 -0700
Subjectuseful macros
Message-ID<15aca137-fa13-441d-af65-60df91c88b04@googlegroups.com>
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?

-- 
Basic Algorithms - a fantastic C resource
http://www.malcolmmclean.site11.com/www



 

[toc] | [next] | [standalone]


#21521

Fromwinndy <jiaoyk@gmail.com>
Date2012-05-29 20:26 -0700
Message-ID<467b41e9-3c51-4052-959f-061c17e4babc@pr3g2000pbb.googlegroups.com>
In reply to#21379
On 5月27日, 上午4时08分, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:
> 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?
>
> --
> Basic Algorithms - a fantastic C resourcehttp://www.malcolmmclean.site11.com/www
>
>

These macros in which header file on linux?

BR

[toc] | [prev] | [next] | [standalone]


#21526

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2012-05-30 00:47 -0700
Message-ID<9461b5b5-79b4-422c-a50c-1b2915629009@googlegroups.com>
In reply to#21521
בתאריך יום רביעי, 30 במאי 2012 04:26:11 UTC+1, מאת winndy:
> On 5月27日, 上午4时08分, Malcolm McLean <malcolm.mcle...@btinternet.com>
> wrote:
> > 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.
> >
> 
> 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 these macros in under a minute.

[toc] | [prev] | [next] | [standalone]


#21547

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-05-30 16:45 +0100
Message-ID<0.bd19cf1c61d059f4f743.20120530164534BST.87ipfdbrkx.fsf@bsb.me.uk>
In reply to#21526
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> בתאריך יום רביעי, 30 במאי 2012 04:26:11 UTC+1, מאת winndy:
>> On 5月27日, 上午4时08分, Malcolm McLean <malcolm.mcle...@btinternet.com>
>> wrote:
>> > 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.
>> >
>> 
>> 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
> 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.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#21550

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-05-30 13:10 -0400
Message-ID<4FC65479.7060004@verizon.net>
In reply to#21547
On 05/30/2012 11:45 AM, Ben Bacarisse wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> 
>> בתאריך יום רביעי, 30 במאי 2012 04:26:11 UTC+1, מאת winndy:
>>> On 5月27日, 上午4时08分, Malcolm McLean <malcolm.mcle...@btinternet.com>
>>> 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. 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.

[toc] | [prev] | [next] | [standalone]


#21557

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-05-30 21:54 +0100
Message-ID<0.ebd3f331a33405ce9533.20120530215420BST.87fwahgzk3.fsf@bsb.me.uk>
In reply to#21550
James Kuyper <jameskuyper@verizon.net> writes:

> On 05/30/2012 11:45 AM, Ben Bacarisse wrote:
>> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
>> 
>>> בתאריך יום רביעי, 30 במאי 2012 04:26:11 UTC+1, מאת winndy:
>>>> On 5月27日, 上午4时08分, Malcolm McLean <malcolm.mcle...@btinternet.com>
>>>> 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>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#21563

From"BartC" <bc@freeuk.com>
Date2012-05-30 23:24 +0100
Message-ID<jq66o5$1gc$1@dont-email.me>
In reply to#21550
"James Kuyper" <jameskuyper@verizon.net> wrote in message
news:4FC65479.7060004@verizon.net...
> 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.

-- 
Bartc 

[toc] | [prev] | [next] | [standalone]


#21564

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-05-30 18:55 -0400
Message-ID<4FC6A57D.5050504@verizon.net>
In reply to#21563
On 05/30/2012 06:24 PM, BartC wrote:
> "James Kuyper" <jameskuyper@verizon.net> wrote in message
> news:4FC65479.7060004@verizon.net...
>> 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.

[toc] | [prev] | [next] | [standalone]


#21565

From"BartC" <bc@freeuk.com>
Date2012-05-31 00:45 +0100
Message-ID<jq6bft$116$1@dont-email.me>
In reply to#21564
"James Kuyper" <jameskuyper@verizon.net> wrote in message
news:4FC6A57D.5050504@verizon.net...
> On 05/30/2012 06:24 PM, BartC wrote:

>> 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.

(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.)

-- 
Bartc 

[toc] | [prev] | [next] | [standalone]


#21566

FromKeith Thompson <kst-u@mib.org>
Date2012-05-30 17:53 -0700
Message-ID<lnmx4pgogp.fsf@nuthaus.mib.org>
In reply to#21563
"BartC" <bc@freeuk.com> writes:
[...]
> 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.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#21572

From"BartC" <bc@freeuk.com>
Date2012-05-31 10:29 +0100
Message-ID<jq7dld$qfa$1@dont-email.me>
In reply to#21566

"Keith Thompson" <kst-u@mib.org> wrote in message
news:lnmx4pgogp.fsf@nuthaus.mib.org...
> "BartC" <bc@freeuk.com> writes:
> [...]
>> 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[i], counts[i]-(M/N));

puts("...");

for (i=N-15; i<N; ++i)
  printf("%d: %d Dev: %d\n",i,counts[i], counts[i]-(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.

-- 
Bartc 

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web