#define and preprocessor magic

Discussion in 'C Programming' started by Marcin Lukasik, Nov 13, 2012.

  1. Hello,

    I have the following in my code:
    #define _TST {100, 200, 300, 400}

    How do I extract any of four elements from that define, and put it into another define? So I would like to have something like this:

    #define VALUE2 _TST[2]
    (but this of course won't work)

    Is there a way of doing it without declaring an array and assigning _TST to it?

    Thank you in advance,
    Marcin
    Marcin Lukasik, Nov 13, 2012
    #1
    1. Advertising

  2. Marcin Lukasik <> writes:
    > I have the following in my code:
    > #define _TST {100, 200, 300, 400}
    >
    > How do I extract any of four elements from that define, and put it
    > into another define? So I would like to have something like this:
    >
    > #define VALUE2 _TST[2]
    > (but this of course won't work)
    >
    > Is there a way of doing it without declaring an array and assigning
    > _TST to it?


    Assuming your compiler supports compound literals, this works for me:

    #include <stdio.h>

    #define TST {100, 200, 300, 400}
    #define VALUE(i) ((int[])TST)

    int main(void) {
    for (int i = 0; i < 4; i ++) {
    printf("VALUE(%d) = %d\n", i, VALUE(i));
    }
    return 0;
    }

    But is there some reason you need that macro? It would probably make
    more sense to define an object and initialize it with the desired
    values:

    #include <stdio.h>

    const int TST[] = {100, 200, 300, 400};

    int main(void) {
    for (int i = 0; i < 4; i ++) {
    printf("TST[%d] = %d\n", i, TST);
    }
    return 0;
    }

    Incidentally, identifiers starting with an underscore and an uppercase
    letter are reserved to the implementation; you should never define such
    identifiers in your own code.

    --
    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, Nov 13, 2012
    #2
    1. Advertising

  3. On Tuesday, November 13, 2012 1:00:19 AM UTC, Keith Thompson wrote:

    > Assuming your compiler supports compound literals, this works for me:
    >
    >
    >
    > #include <stdio.h>
    >
    >
    >
    > #define TST {100, 200, 300, 400}
    >
    > #define VALUE(i) ((int[])TST)


    Thank you, this does the trick!


    > But is there some reason you need that macro? It would probably make
    >
    > more sense to define an object and initialize it with the desired
    >
    > values:


    You're 100% right and I will do this eventually. I didn't write the code myself, many people have contributed and we ended up with the same variables being used twice, but declared differently... It's a temporary fix.


    One last question... when I change the type to float, and do:
    #define TST {100.01, 200.002, 300.03, 400.04}
    #define VALUE(i) ((float[]) TST)

    printf("VALUE(2): %f\n", VALUE(2)) returns "VALUE(2): 300.029999".
    Why?

    I'm using gcc, I only use -Wall flag.

    Thanks,
    Marcin
    Marcin Lukasik, Nov 13, 2012
    #3
  4. Marcin Lukasik <> writes:
    <snip>
    > One last question... when I change the type to float, and do:
    > #define TST {100.01, 200.002, 300.03, 400.04}
    > #define VALUE(i) ((float[]) TST)
    >
    > printf("VALUE(2): %f\n", VALUE(2)) returns "VALUE(2): 300.029999".
    > Why?


    There are many numbers that can't be represented exactly when stored as
    floating point objects. Exactly which ones depends on the floating
    point representation used, but 300.03 can't be represented exactly using
    binary floating point.

    The main benefit of using floating point is to gain range at the expense
    of precision, but it is often used simply to have a way to represent
    fractional numbers. When used for that purpose, the loss of precision
    is just annoying, but C does not have an exact non-integer numeric type.

    --
    Ben.
    Ben Bacarisse, Nov 13, 2012
    #4
  5. Marcin Lukasik

    James Kuyper Guest

    On 11/13/2012 07:54 AM, Marcin Lukasik wrote:
    > On Tuesday, November 13, 2012 1:00:19 AM UTC, Keith Thompson wrote:
    >
    >> Assuming your compiler supports compound literals, this works for me:
    >>
    >>
    >>
    >> #include <stdio.h>
    >>
    >>
    >>
    >> #define TST {100, 200, 300, 400}
    >>
    >> #define VALUE(i) ((int[])TST)

    >
    > Thank you, this does the trick!
    >
    >
    >> But is there some reason you need that macro? It would probably make
    >>
    >> more sense to define an object and initialize it with the desired
    >>
    >> values:

    >
    > You're 100% right and I will do this eventually. I didn't write the code myself, many people have contributed and we ended up with the same variables being used twice, but declared differently... It's a temporary fix.
    >
    >
    > One last question... when I change the type to float, and do:
    > #define TST {100.01, 200.002, 300.03, 400.04}
    > #define VALUE(i) ((float[]) TST)
    >
    > printf("VALUE(2): %f\n", VALUE(2)) returns "VALUE(2): 300.029999".
    > Why?


    The only numbers that can be represented exactly in double precision
    floating point are those between DBL_MIN and DBL_MAX which are of the
    form mantissa*pow(FLT_RADIX,exponent), where mantissa and exponent are
    both integers, and mantissa must be less than FLT_RADIX/DBL_EPSILON.
    DBL_MIN, DBL_MAX, FLT_RADIX, and DBL_EPSILON are all macros #defined in
    <float.h>. 300.03 is 30003/100, which cannot be put into that form
    unless FLT_RADIX is divisible by 10. On almost all machines, FLT_RADIX
    is 2; on almost all of the other machines, FLT_RADIX is a power of 2,
    usually 16.

    Have a look at "What every computer scientist should know about floating
    point arithmetic" by D. Goldberg. It's available on the web in various
    formats. The first one that I was able to find was provided by Julian V.
    Noble:
    http://galileo.phys.virginia.edu/classes/551.jvn.fall01/

    --
    James Kuyper
    James Kuyper, Nov 13, 2012
    #5
  6. On Tuesday, 13 November 2012 13:11:23 UTC, Ben Bacarisse wrote:
    >
    > The main benefit of using floating point is to gain range at the expense
    > of precision, but it is often used simply to have a way to represent
    > fractional numbers. When used for that purpose, the loss of precision
    > is just annoying, but C does not have an exact non-integer numeric type.


    Thank you Ben.
    But does this mean that VALUE(2) stores 300.029999 or 300.03?
    In other words do I loose precision by doing ((float[]) TST) or by formatting it as %f in printf?

    Marcin
    Marcin Lukasik, Nov 13, 2012
    #6
  7. Marcin Lukasik <> writes:

    > On Tuesday, 13 November 2012 13:11:23 UTC, Ben Bacarisse wrote:
    >>
    >> The main benefit of using floating point is to gain range at the expense
    >> of precision, but it is often used simply to have a way to represent
    >> fractional numbers. When used for that purpose, the loss of precision
    >> is just annoying, but C does not have an exact non-integer numeric type.

    >
    > Thank you Ben.
    > But does this mean that VALUE(2) stores 300.029999 or 300.03?


    Neither! It is stored as the closest floating point number to 300.03.
    Exactly what that is is probably not important to you, but you can work
    it out if you really need to know. Read the excellent paper that James
    directed you to for all the details (in my opinion, somewhat more than
    every programmer needs to know, but extra knowledge is never a problem).

    > In
    > other words do I loose precision by doing ((float[]) TST) or by
    > formatting it as %f in printf?


    %f confuses the issue because using less precision for output can make
    it seem more accurate. %.2f will print 300.03 because that's the
    closest 2-digit decimal representation of the value that's stored
    internally.

    By the way, "modern" C has a format (%a) that lets you print out the
    exact internal value but it won't be easy to understand what you get
    until you have read more about floating point numbers.

    --
    Ben.
    Ben Bacarisse, Nov 13, 2012
    #7
  8. Marcin Lukasik

    Eric Sosman Guest

    On 11/13/2012 8:28 AM, Marcin Lukasik wrote:
    > On Tuesday, 13 November 2012 13:11:23 UTC, Ben Bacarisse wrote:
    >>
    >> The main benefit of using floating point is to gain range at the expense
    >> of precision, but it is often used simply to have a way to represent
    >> fractional numbers. When used for that purpose, the loss of precision
    >> is just annoying, but C does not have an exact non-integer numeric type.

    >
    > Thank you Ben.
    > But does this mean that VALUE(2) stores 300.029999 or 300.03?
    > In other words do I loose precision by doing ((float[]) TST) or by formatting it as %f in printf?


    Both, probably. (Also, the word you want is "lose.")

    Most systems nowadays store floating-point values in base two,
    meaning that the number actually stored has the value N/D where
    N and D are integers and D is a power of two. You can easily see
    that no such N/D can be equal to 30003/100; it's exactly the same
    problem familiar base-ten notation runs into with values like 22/7.

    Most systems nowadays round the N of a `float' value to 24
    base-two digits, just as you might round 22/7 to four base-ten
    digits and get 3.143. Your `300.03' is probably 9831383/32768,
    which is (if I haven't goofed) the nearest N/D such that N uses
    only 24 bits and D is a power of two. The exact value of this
    fraction is 300.029998779296875, closer than any other `float'
    to the desired 300.03 but not exactly equal to it.

    The "%f" conversion introduces a further approximation and
    an additional error. Unadorned "%f" always prints six digits
    after the decimal point, rounding the number as needed -- this
    spares you from seeing horrors like "300.029998779296875". If
    you know your numbers aren't good to six decimal places you can
    use "%.2f" to get two places, or "%.5f" for five places, and so
    on. Your `float' probably has 24 base-two digits, equivalent to
    a little more than 7 decimal digits, so for values near 300 you
    can't expect digits after the fourth decimal place to mean much.
    If you were to round to four places with "%.4f" you'd probably
    see a value you'd find less confusing.

    Don't, by the way, make the mistake of thinking that because
    a value is *stored* to seven-and-change decimal digits' precision
    that it is *accurate* to that degree. If you weigh yourself in
    pounds you'll probably get a three-digit number, so with seven
    digits' precision you can tack on four decimal places, right?
    How much faith should you put in that rightmost decimal place?

    --
    Eric Sosman
    d
    Eric Sosman, Nov 13, 2012
    #8
  9. Marcin Lukasik

    James Kuyper Guest

    On 11/13/2012 08:28 AM, Marcin Lukasik wrote:
    > On Tuesday, 13 November 2012 13:11:23 UTC, Ben Bacarisse wrote:
    >>
    >> The main benefit of using floating point is to gain range at the expense
    >> of precision, but it is often used simply to have a way to represent
    >> fractional numbers. When used for that purpose, the loss of precision
    >> is just annoying, but C does not have an exact non-integer numeric type.

    >
    > Thank you Ben.
    > But does this mean that VALUE(2) stores 300.029999 or 300.03?
    > In other words do I loose precision by doing ((float[]) TST) or by formatting it as %f in printf?


    300.03 is a constant of type double, and on most systems cannot be
    exactly represented in that type. For instance, on my system, the
    compiler converts 300.03 into 1319545894726533*pow(2,-42), which is the
    closest approximation it can get to that value using double precision
    floating point. Precision is lost at the point of that conversion. When
    you convert it float, additional precision is lost. Passing it to
    printf() causes it to be converted back to double. This will generally
    not lose you any additional precision, but it cannot restore the bits
    that were lost by converting to float. Printing it with %f looses some
    precision, but if you give it a floating point format with sufficiently
    many significant digits, printf() can display the exact value that was
    passed to it.
    --
    James Kuyper
    James Kuyper, Nov 13, 2012
    #9
  10. Marcin Lukasik

    BartC Guest

    "Marcin Lukasik" <> wrote in message
    news:...

    > One last question... when I change the type to float, and do:
    > #define TST {100.01, 200.002, 300.03, 400.04}
    > #define VALUE(i) ((float[]) TST)
    >
    > printf("VALUE(2): %f\n", VALUE(2)) returns "VALUE(2): 300.029999".
    > Why?


    100.01 etc can't be exactly represented in binary floating as has been
    explained.

    If that .01 is important, store as a string ("100.01") or store as an
    integer (10001) with an implied scale factor of 1/100.

    (Depending on what the numbers will be used for, you might still get
    problems when you eventually do arithmetic on these values if they are
    converted to floating point. But you can sometimes work around such issues.)

    --
    Bartc
    BartC, Nov 13, 2012
    #10
  11. Marcin Lukasik <> writes:
    [...]
    > One last question... when I change the type to float, and do:
    > #define TST {100.01, 200.002, 300.03, 400.04}
    > #define VALUE(i) ((float[]) TST)

    [...]

    Most numeric software in C uses type double rather than float.
    It (usually) has substantially more precision, and on many systems
    operations on double are not much more expensive than operations
    on float.

    If you need more precision than double, you can use long double --
    but on some systems long double is no wider than double.

    This won't avoid the issues discussed in the rest of this thread; it
    will just push your errors a few more places past the decimal point.

    --
    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, Nov 13, 2012
    #11
  12. Marcin Lukasik

    Paul N Guest

    On Nov 13, 12:46 am, Marcin Lukasik <> wrote:
    > Hello,
    >
    > I have the following in my code:
    > #define _TST {100, 200, 300, 400}
    >
    > How do I extract any of four elements from that define, and put it into another define? So I would like to have something like this:
    >
    > #define VALUE2 _TST[2]
    > (but this of course won't work)
    >
    > Is there a way of doing it without declaring an array and assigning _TST to it?
    >
    > Thank you in advance,
    > Marcin


    I'm sure there must be some way of doing this (not that you actually
    appear to need it, from your comments elsethread). The best I've
    managed so far is:

    #define f1(a, b, c, d) a
    #define f2(a, b, c, d) b
    #define f3(a, b, c, d) c
    #define f4(a, b, c, d) d

    #define _TST {100, 200, 300, 400}

    #define g(v, x) f##x(v)

    g(_TST, 2)

    but this leaves in the brackets on the first and last items.
    Paul N, Nov 13, 2012
    #12
  13. pete <> writes:
    > Keith Thompson wrote:
    >> Marcin Lukasik <> writes:
    >> [...]
    >> > One last question... when I change the type to float, and do:
    >> > #define TST {100.01, 200.002, 300.03, 400.04}
    >> > #define VALUE(i) ((float[]) TST)

    >> [...]
    >>
    >> Most numeric software in C uses type double rather than float.
    >> It (usually) has substantially more precision, and on many systems
    >> operations on double are not much more expensive than operations
    >> on float.
    >>
    >> If you need more precision than double, you can use long double --
    >> but on some systems long double is no wider than double.
    >>
    >> This won't avoid the issues discussed in the rest of this thread; it
    >> will just push your errors a few more places past the decimal point.

    >
    > I tend to think of double
    > as the more natural type than float,
    > because float promotes to double
    > in the default argument promotions.


    Yes, but that's pretty much relevant only for variadic functions, mostly
    the *printf() family. (It's also relevant for functions with old-style
    declarations, but such functions are themselves largely irrelevant.)

    --
    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, Nov 14, 2012
    #13
  14. Keith Thompson <> wrote:
    > pete <> writes:


    (snip)
    >> I tend to think of double
    >> as the more natural type than float,
    >> because float promotes to double
    >> in the default argument promotions.


    > Yes, but that's pretty much relevant only for variadic functions, mostly
    > the *printf() family. (It's also relevant for functions with old-style
    > declarations, but such functions are themselves largely irrelevant.)


    I still remember early in the ANSI C days, upgrading to, I believe
    the Microsoft C compiler 5.0, from the previous non-ANSI compiler.

    Then, since I could, adding function prototypes and the program wouldn't
    work anymore! I forget the exact combination, but it was related to the
    promotion being different with and without prototypes.

    -- glen
    glen herrmannsfeldt, Nov 14, 2012
    #14
  15. pete <> writes:

    > Keith Thompson wrote:
    >>
    >> Marcin Lukasik <> writes:
    >> [...]
    >> > One last question... when I change the type to float, and do:
    >> > #define TST {100.01, 200.002, 300.03, 400.04}
    >> > #define VALUE(i) ((float[]) TST)

    >> [...]
    >>
    >> Most numeric software in C uses type double rather than float.
    >> It (usually) has substantially more precision, and on many systems
    >> operations on double are not much more expensive than operations
    >> on float.
    >>
    >> If you need more precision than double, you can use long double --
    >> but on some systems long double is no wider than double.
    >>
    >> This won't avoid the issues discussed in the rest of this thread; it
    >> will just push your errors a few more places past the decimal point.

    >
    > I tend to think of double
    > as the more natural type than float,
    > because float promotes to double
    > in the default argument promotions.


    That's one reason but another to me stronger reason is that unadorned
    floating point constants are of type double. This, along with the
    usual arithmetic conversions, means that floats often get converted to
    double (if only conceptually) in expressions like VALUE(2) + 1.

    --
    Ben.
    Ben Bacarisse, Nov 14, 2012
    #15
  16. Marcin Lukasik

    Guest

    On Tuesday, November 13, 2012 5:43:13 AM UTC-8, Ben Bacarisse wrote:
    > Marcin Lukasik <> writes:
    > > But does this mean that VALUE(2) stores 300.029999 or 300.03?

    > Neither! It is stored as the closest floating point number to 300.03. Exactly
    > what that is is probably not important to you, but you can work it out if you
    > really need to know.


    It's likely to have "5" as the last digit...

    > Read the excellent paper that James directed you to for
    > all the details (in my opinion, somewhat more than every programmer needs to
    > know, but extra knowledge is never a problem).


    If by "every programmer", you mean somebody who might have any kind
    of programming task thrown at them, then the knowledge is definitely
    helpful, in at least you'll know why your financial application is
    possibly giving wrong answers, but there's not enough information
    there to actually proactively fix the problem, so just another busted
    program, but you get paid the same amount anyway, so who cares except
    the user...

    ---
    William Ernest Reid
    , Nov 15, 2012
    #16
  17. On Thu, 15 Nov 2012 05:04:44 -0800 (PST), wrote:

    >On Tuesday, November 13, 2012 5:43:13 AM UTC-8, Ben Bacarisse wrote:
    >> Marcin Lukasik <> writes:
    >> > But does this mean that VALUE(2) stores 300.029999 or 300.03?

    >> Neither! It is stored as the closest floating point number to 300.03. Exactly
    >> what that is is probably not important to you, but you can work it out if you
    >> really need to know.

    >
    >It's likely to have "5" as the last digit...


    Not on any IEEE system where double is 8 bytes.


    --
    Remove del for email
    Barry Schwarz, Nov 15, 2012
    #17
  18. Barry Schwarz <> writes:
    > On Thu, 15 Nov 2012 05:04:44 -0800 (PST), wrote:
    >>On Tuesday, November 13, 2012 5:43:13 AM UTC-8, Ben Bacarisse wrote:
    >>> Marcin Lukasik <> writes:
    >>> > But does this mean that VALUE(2) stores 300.029999 or 300.03?
    >>> Neither! It is stored as the closest floating point number to 300.03. Exactly
    >>> what that is is probably not important to you, but you can work it out if you
    >>> really need to know.

    >>
    >>It's likely to have "5" as the last digit...

    >
    > Not on any IEEE system where double is 8 bytes.


    Oh?

    As far as I can see, the last non-zero digit in the exact decimal
    representation of a representable floating-point number is always
    5 unless the number is an exact integer. (All such numbers are an
    integer multiple of a power of 2.0.)

    You can see this using printf() *if* you use enough digits *and*
    the printf() implementation prints exact values.

    --
    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, Nov 15, 2012
    #18
  19. Marcin Lukasik

    James Kuyper Guest

    On 11/15/2012 02:51 PM, Barry Schwarz wrote:
    > On Thu, 15 Nov 2012 05:04:44 -0800 (PST), wrote:
    >
    >> On Tuesday, November 13, 2012 5:43:13 AM UTC-8, Ben Bacarisse wrote:
    >>> Marcin Lukasik <> writes:
    >>>> But does this mean that VALUE(2) stores 300.029999 or 300.03?
    >>> Neither! It is stored as the closest floating point number to 300.03. Exactly
    >>> what that is is probably not important to you, but you can work it out if you
    >>> really need to know.

    >>
    >> It's likely to have "5" as the last digit...

    >
    > Not on any IEEE system where double is 8 bytes.


    Could you explain that assertion?
    IEEE double precision can only represent a value exactly if it can be
    expressed as an integer times a power of 2. Such a value has a
    fractional part only if that power is negative. If a fraction with a
    denominator which is a power of two has any non-zero digits, the last
    such digit is always 5.

    As I've already mentioned, I've already determined that on my system
    300.03 is approximated by 1319545894726533*pow(2,-42); therefore 42
    digits after the decimal point is sufficient to show the last non-zero
    digit:

    ~/testprog(52) cat three.c
    #include <stdio.h>
    #ifndef __STDC_IEC_559__
    #error Does not conform to IEC 60559 specifications from annex F
    #endif

    int main(void)
    {
    printf("%zu, %.42f\n", sizeof 300.03, 300.03);
    return 0;
    }
    ~/testprog(53) gcc -std=c99 -pedantic -Wall -Wpointer-arith -Wcast-align
    -Wstrict-prototypes -Wmissing-prototypes three.c -lm -o three
    ~/testprog(54) three
    8, 300.029999999999972715158946812152862548828125
    James Kuyper, Nov 15, 2012
    #19
  20. On Thu, 15 Nov 2012 12:16:49 -0800, Keith Thompson <>
    wrote:

    >Barry Schwarz <> writes:
    >> On Thu, 15 Nov 2012 05:04:44 -0800 (PST), wrote:
    >>>On Tuesday, November 13, 2012 5:43:13 AM UTC-8, Ben Bacarisse wrote:
    >>>> Marcin Lukasik <> writes:
    >>>> > But does this mean that VALUE(2) stores 300.029999 or 300.03?
    >>>> Neither! It is stored as the closest floating point number to 300.03. Exactly
    >>>> what that is is probably not important to you, but you can work it out if you
    >>>> really need to know.
    >>>
    >>>It's likely to have "5" as the last digit...

    >>
    >> Not on any IEEE system where double is 8 bytes.

    >
    >Oh?
    >
    >As far as I can see, the last non-zero digit in the exact decimal
    >representation of a representable floating-point number is always
    >5 unless the number is an exact integer. (All such numbers are an
    >integer multiple of a power of 2.0.)
    >
    >You can see this using printf() *if* you use enough digits *and*
    >the printf() implementation prints exact values.


    What you say is obviously true in the mathematical sense.

    But in the practical sense, that doesn't seem to matter when trying to
    use the values. With %30.20f, my system shows
    300.02999999999997000000 and that remains unchanged even after
    subtracting 2.8E-14 which should have had some effect on that 7.
    Multiplying by 100 produces 30002.99999999999600000000.

    Both serve to show that you cannot depend on the last non-zero digit
    being well-behaved once you exceed DECIMAL_DIG.

    --
    Remove del for email
    Barry Schwarz, Nov 16, 2012
    #20
    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. Preprocessor magic needed

    , Mar 17, 2006, in forum: C Programming
    Replies:
    8
    Views:
    341
    CBFalconer
    Mar 20, 2006
  2. Replies:
    8
    Views:
    376
    CBFalconer
    Mar 20, 2006
  3. mathieu
    Replies:
    8
    Views:
    458
    Alf P. Steinbach
    Aug 6, 2009
  4. mathieu
    Replies:
    1
    Views:
    526
    mathieu
    Aug 6, 2009
  5. Giles Bowkett
    Replies:
    9
    Views:
    404
    Giles Bowkett
    Dec 17, 2007
Loading...

Share This Page