Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > #define and preprocessor magic

Reply
Thread Tools

#define and preprocessor magic

 
 
Marcin Lukasik
Guest
Posts: n/a
 
      11-13-2012
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
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      11-13-2012
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[i])

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[i]);
}
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) kst- <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"
 
Reply With Quote
 
 
 
 
Marcin Lukasik
Guest
Posts: n/a
 
      11-13-2012
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[i])


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[i])

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

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

Thanks,
Marcin
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-13-2012
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[i])
>
> 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.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      11-13-2012
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[i])

>
> 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[i])
>
> 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/cla...51.jvn.fall01/

--
James Kuyper
 
Reply With Quote
 
Marcin Lukasik
Guest
Posts: n/a
 
      11-13-2012
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[i]) or by formatting it as %f in printf?

Marcin
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-13-2012
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[i]) 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.
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      11-13-2012
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[i]) 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
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      11-13-2012
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[i]) 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
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      11-13-2012
"Marcin Lukasik" <> wrote in message
news:1ad1ff30-e550-4ccc-9f24-...

> 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[i])
>
> 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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Preprocessor magic needed claus.tondering@gmail.com C++ 8 03-20-2006 10:52 AM
Preprocessor magic needed claus.tondering@gmail.com C Programming 8 03-20-2006 10:52 AM
Compiler error occurred when try to use a flexible template expression in preprocessor definesCompiler error occurred when try to use a flexible template expression in preprocessor defines snnn C++ 6 03-14-2005 04:09 PM
Cinema.Craft.Encoder.SP.v2.70.01.05, Magic.Bullet.Editor.v.1.01.for.Avid.Xpress.Pro, Magic.Bullet.Editor.v.1.01.for.Premiere.Pro, Magic.Bullet.Editor.v.1.01.for.Sony.Vegas, Avid.Xpress.Pro.HD.v5.0 1CD, Sony.Vegas.v5.0d, ola DVD Video 0 01-14-2005 10:53 AM
preprocessor, token concatenation, no valid preprocessor token Cronus C++ 1 07-14-2004 11:10 PM



Advertisments
 



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