useful macros

Discussion in 'C Programming' started by Malcolm McLean, May 26, 2012.

  1. 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
    Malcolm McLean, May 26, 2012
    #1
    1. Advertising

  2. Malcolm McLean

    winndy Guest

    On 5ÔÂ27ÈÕ, ÉÏÎç4ʱ08·Ö, Malcolm McLean <>
    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
    winndy, May 30, 2012
    #2
    1. Advertising

  3. בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
    > On 5月27æ—¥, 上åˆ4æ—¶08分, Malcolm McLean <>
    > 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 thesemacros in under a minute.
    Malcolm McLean, May 30, 2012
    #3
  4. Malcolm McLean <> writes:

    > בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
    >> On 5月27æ—¥, 上åˆ4æ—¶08分, Malcolm McLean <>
    >> 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.
    Ben Bacarisse, May 30, 2012
    #4
  5. Malcolm McLean

    James Kuyper Guest

    On 05/30/2012 11:45 AM, Ben Bacarisse wrote:
    > Malcolm McLean <> writes:
    >
    >> בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
    >>> On 5月27æ—¥, 上åˆ4æ—¶08分, Malcolm McLean <>
    >>> 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.
    James Kuyper, May 30, 2012
    #5
  6. James Kuyper <> writes:

    > On 05/30/2012 11:45 AM, Ben Bacarisse wrote:
    >> Malcolm McLean <> writes:
    >>
    >>> בת×ריך ×™×•× ×¨×‘×™×¢×™, 30 במ××™ 2012 04:26:11 UTC+1, מ×ת winndy:
    >>>> On 5月27æ—¥, 上åˆ4æ—¶08分, Malcolm McLean <>
    >>>> 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.
    Ben Bacarisse, May 30, 2012
    #6
  7. Malcolm McLean

    BartC Guest

    "James Kuyper" <> wrote in message
    news:...
    > 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
    BartC, May 30, 2012
    #7
  8. Malcolm McLean

    James Kuyper Guest

    On 05/30/2012 06:24 PM, BartC wrote:
    > "James Kuyper" <> wrote in message
    > news:...
    >> 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.
    James Kuyper, May 30, 2012
    #8
  9. Malcolm McLean

    BartC Guest

    "James Kuyper" <> wrote in message
    news:...
    > 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
    BartC, May 31, 2012
    #9
  10. "BartC" <> 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) <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"
    Keith Thompson, May 31, 2012
    #10
  11. Malcolm McLean

    BartC Guest

    "Keith Thompson" <> wrote in message
    news:...
    > "BartC" <> 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, 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.

    --
    Bartc
    BartC, May 31, 2012
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben Pfaff

    Re: possible useful macros...

    Ben Pfaff, May 23, 2012, in forum: C Programming
    Replies:
    0
    Views:
    302
    Ben Pfaff
    May 23, 2012
  2. John Gordon

    Re: possible useful macros...

    John Gordon, May 23, 2012, in forum: C Programming
    Replies:
    3
    Views:
    299
    Phil Carmody
    Jun 11, 2012
  3. Kaz Kylheku

    Re: possible useful macros...

    Kaz Kylheku, May 23, 2012, in forum: C Programming
    Replies:
    0
    Views:
    240
    Kaz Kylheku
    May 23, 2012
  4. Lanarcam

    Re: possible useful macros...

    Lanarcam, May 23, 2012, in forum: C Programming
    Replies:
    1
    Views:
    230
    Bartc
    May 23, 2012
  5. Ike Naar

    Re: possible useful macros...

    Ike Naar, May 23, 2012, in forum: C Programming
    Replies:
    0
    Views:
    225
    Ike Naar
    May 23, 2012
Loading...

Share This Page