PDA

View Full Version : Marching coordinates

joerg
04-11-2007, 11:30 AM
x[0]=0;
y[0]=0;

for(i=0;i<N-1;i++)
{
if(x[i]<1) x[i+1]=x[i]+Vx*dt;
else x[i+1]=x[i]-Vx*dt;

Help! I want the coordinates x[i] change from 0 over +1 to -1 and back as often as i<N. The program counts from 0 up to 1 - O.K. - but then oscillates from 1 to 0.9 and so on.

twomers
04-11-2007, 11:38 AM
You could do the following -

int main( void )
{
int num[] = { -1, 0, 1 }, i, max=10;

for ( i=1; i<max; i++ )
{
printf( "&#37;d ", num[i%3] );
}

return 0;
}

And please consider using code tags in the future. It'll keep many of us happier :)

joerg
04-11-2007, 12:04 PM
Thank you, but I forgot to mention, that the x[i] are real numbers, ranging over [-1:1]
I want to create something like 0.0, 0.1, ...,0.9 , 1.0 , 0.9 , ... ,0.0 , -0.9 , -0.8 , ... , -1.0 , -0.9 ,... and so on as far as i<N

Wlii i get another chance ?

joerg

IsmAvatar2
04-11-2007, 12:08 PM
Could you please clarify the last part of the oscillation? You say:
0.0 , -0.9 , -0.8 , ... , -1.0 , -0.9
But there's a bit of a skip from 0.0 to -0.9, and similarly, you cannot count up from -0.9 and hope to reach -1.0.

joerg
04-11-2007, 12:14 PM

It has to look like this: 0.0, 0.1 ,... ,1.0 ,0.9 ,...0.1 , 0.0 ,-0.1 ,-0.2 ,... ,-1.0 ,-0.9 ,-0.8 ,... ans so on.

Is there a third chance for me ?

joerg

IsmAvatar2
04-11-2007, 12:24 PM
Here's the dependant coding of it - that is, each entry is dependant on the previous entry.

double val = 0.0
double inc = 0.1
int N = 100;
double x[N];

for (int i = 0; i < N; i++) {
val += inc; //increase oscillation position
if ((val == 1.0) || (val == -1.0)) inc = -inc; //reverse direction
x[i] = val;
}

twomers
04-11-2007, 12:36 PM
Do you understand looping? If so this should be trivial.

First things first - try to get your program to count from 0 to 1 in steps of 0.1. When you have that try to modify your code to get it to work from -1 to +1. Then worry about making it over and over and over again.

IsmAvatar2
04-11-2007, 12:41 PM
@twomers: that won't work, because then it won't oscillate, it will only modulate. Once it counts up to +1, it needs to start counting back down again.

@joerg: Here's a more dynamic solution. It's independant of previous entries, meaning that you can just plug in any value and it will dynamically compute it without having to go back through the entire list, so it has a runtime of O(1), rather than my previous solution, which had a runtime of O(n).

int N = 100;
double x[N];
for (int i = 0; i < N; i++) {
int v = (i + 10) &#37; 40;
if (v <= 20) x[i] = (double)(v - 10) / 10.0;
if (v > 20) x[i] = (double)(30 - v) / 10.0;
}
I was also considering a solution that used memoization, but realized that I could just modulate over the computation.

twomers
04-11-2007, 12:47 PM
>> @twomers: that won't work, because then it won't oscillate, it will only modulate. Once it counts up to +1, it needs to start counting back down again.

I understand. The OP is probably a beginner at programming, so he has to get his mind into doing things in steps and building on what he has written! I was trying to encourage him to do it himself, and hence to become a better programmer.

edit
>>int N = 100;
>>double x[N];

<nvm that>

sigh

int main( void )
{
double i, di = -0.1;
int num=0;

for ( i=-1.0; num<100; i+=di, num++ )
{
printf( "&#37;f ", i );

if ( i<-0.9 || i>0.9 )
di *= -1;
}

return 0;
}

Enjoy.

IsmAvatar2
04-11-2007, 12:55 PM
#define N 100
double x[N];

;)

brewbuck
04-11-2007, 01:47 PM
Whenever the value reaches 1.0 or -1.0, negate the value of dt (or Vx, one of the two).

dwks
04-11-2007, 02:22 PM
#define N 100
double x[N];

;)

#define N 100

enum { N = 100 };

const int N = 100;

Here's one, though I've changed my opinions since then: http://cboard.cprogramming.com/showthread.php?t=85992

brewbuck
04-11-2007, 02:32 PM
#ifndef N
#define N 100
#endif

Advantages: The user can override the preprocessor definition at compile-time, without editing the source.
Disadvantages: Literal substitution of macros can cause weird effects in certain situations. The debugger (usually) has no idea about defined values, so debugging is harder.

enum { N = 100; }

Advantages: An enum is a real type, so the compiler can do type checking. The debugger can display the symbolic values, provided you've given everything an appropriate type instead of just "int."
Disadvantages: An enumeration really shouldn't be used unless there are multiple related values to declare. Goes against intended use of enum, and might be obfuscatory.

const int N = 100;

Disadvantages: The variable is "real," meaning you can take its address. This means you can coerce the type to non-const, and then change the supposedly "constant" value at runtime (that is, if it doesn't crash). NOTE: big difference from what it means in C++!

I tend to go with #define. The ability to override the constants at compile time is just too convenient most of the time.

dwks
04-11-2007, 02:46 PM
I generally use:

Named enums for multiple related values, e.g.:

enum type_t {
TYPE_NUMBER,
TYPE_STRING,
TYPES
};
This is because:

The numbers are incremented automatically, so adding another value is easy.
You can add a variable at the end which is a count of all the preceding values.

Note that this is the intended use of enums.
Anonymous enums for constant values, e.g.:

enum {
STRING_LEN = BUFSIZ
};
This is the controversial usage of enum. I use enum instead of #defines because the compiler checks the values rather than the preprocessor, which is rather blind. I suppose I could use constant values, but -- force of habit.
#defines for strings, e.g.:

#define VERSION "program version 1.0.0"
That way I can use the preprocessor string concatentation:

fprintf(stderr, VERSION "\n"
"\nusage: ...\n");

I just knew that this was going to start a debate . . .

twomers
04-11-2007, 02:54 PM
Wow. A doubly listed list! You should be proud, dwks!

>> STRING_LEN = BUFSIZ
Is BUFSIZ a #define ... ? I would be very amused if it was.

dwks
04-11-2007, 03:02 PM
It is. ;) It's a minimum of 512 AFAIK, though on some of my computers it's 8192. It's used for setbuf etc. I like to use it as the amount of memory to increase a string by when I run out (see codeform).

What's that about a double-linked list? (I think it's "double-linked" and not "doubly-linked" BTW. It's like "fine-toothed comb", which is actually "fine tooth-comb"; there was once a fine type of tooth-comb. :D )

brewbuck
04-11-2007, 03:03 PM
Wow. A doubly listed list! You should be proud, dwks!

>> STRING_LEN = BUFSIZ
Is BUFSIZ a #define ... ? I would be very amused if it was.

I think it's exactly that realization that eventually convinces most people to just use #define :-)

dwks
04-11-2007, 03:08 PM
Well, here are the arguments that I'm aware of (for anonymous enums):

FOR
enum values are compile-time constants, so the compiler can give you better error messages if, for example, you try something like this:

enum { X = 10 };
int X = 10; /* whoops */

Also, debuggers are better with enum values (which is more readable, 10 or X?)

AGAINST
enums are not supposed to be used in that way, so it could become harder to read or something.

And for #defines:

FOR
#defines are processed by the preprocessor, so you can change their values via the command line and Makefiles etc.

AGAINST
See FOR for enums.

I think I'd prefer to use enums for values like string lengths, but #defines for things like the path to ls (that you might want to change without edited the source).

Basically a restatement of brewbuck's post above.

twomers
04-11-2007, 03:12 PM
>> What's that about a double-linked list? (I think it's "double-linked" and not "doubly-linked" BTW. It's like "fine-toothed comb", which is actually "fine tooth-comb"; there was once a fine type of tooth-comb. )

It was in your first point where it went into 1(a) and 1(b). Very impressive. Two lists. But in one. And I said a doubly listed list. Not linked.

>> It is.
But then why not simply use that instead of your enum? Seems similar to hearing a zebra run!

dwks
04-11-2007, 03:20 PM
>> What's that about a double-linked list? (I think it's "double-linked" and not "doubly-linked" BTW. It's like "fine-toothed comb", which is actually "fine tooth-comb"; there was once a fine type of tooth-comb. )

It was in your first point where it went into 1(a) and 1(b). Very impressive. Two lists. But in one. And I said a doubly listed list. Not linked.

>> It is.
But then why not simply use that instead of your enum? Seems similar to hearing a zebra run!
Sorry, I'm so used to reading "double-linked list" that I see it everywhere . . . but I bet you'd have said "doubly-linked list" if you'd mentioned one. :)

Because I might want to change it.

enum { STRING_LEN = BUFSIZ*2 };
enum { STRING_LEN = USHRT_MAX };

brewbuck
04-11-2007, 03:29 PM
And for #defines:

AGAINST
See FOR for enums.

#define X 10
int X = 10;

The preprocessor will turn that into "int 10 = 10;" and the compiler will barf. No problem there.

I think I'd prefer to use enums for values like string lengths, but #defines for things like the path to ls (that you might want to change without edited the source).

I actually use "const char *" for constant strings. The problem is this: a string literal has type "char *" (i.e. NOT const), but on most platforms it resides in read-only memory (despite the fact that it isn't known to be "const") I.e.:

/* This will probably crash. */
char *foo = "Hello";
foo[0] = 'A';

Whereas if you assign it to a const char * from the get-go:

const char *foo = "Hello";
foo[0] = 'A'; /* Compiler throws error */

This saves you from the peril of passing a string literal to a function which takes a non-const char pointer, which then tries to modify the string, which then crashes. Instead you get a compile error and go fix the problem.

dwks
04-11-2007, 03:33 PM
The preprocessor will turn that into "int 10 = 10;" and the compiler will barf. No problem there.

No, but it will give you an error like "invalid variable name" you you'll think, "what? X? invalid???". Whereas if you have an enum by the same name it will give you a much more palatable error. (I should imagine anyway.)

I'm aware of the const-ness of string literals. I just use #defines for them because I like inserting them into strings with the preprocessor's string concatenation. :)

fprintf(stderr, PROGRAM " version " VERSION " by " AUTHOR "\n");

brewbuck
04-11-2007, 03:39 PM
I'm aware of the const-ness of string literals. I just use #defines for them because I like inserting them into strings with the preprocessor's string concatenation. :)

fprintf(stderr, PROGRAM " version " VERSION " by " AUTHOR "\n");

That's fine until one day one of the strings has a "%s" or something in it.

Why not just:

fprintf(stderr, "%s version %s by %s\n", PROGRAM, VERSION, AUTHOR);

dwks
04-11-2007, 04:04 PM
Because I usually use puts() instead. It's a case of premature optimization. :) You're right, it's not a good idea . . . I think I'll avoid it in the future.

I still like enums though. :) The main reason being that, in C++, you can put them in namespaces etc. No doubt const variables would be a better idea in that case, though.

It was in your first point where it went into 1(a) and 1(b). Very impressive. Two lists. But in one.
You could always say a "nested list". :)

brewbuck
04-11-2007, 04:08 PM
Because I usually use puts() instead. It's a case of premature optimization. :) You're right, it's not a good idea . . . I think I'll avoid it in the future.

Well, I agree that string concatenation is a pretty useful thing to do. The problem is really printf-specific -- the format string to printf() should always be a literal in my opinion so that you can SEE what it is and make sure there are no stray conversion specifiers lurking in it. But I use string concatenation all the time when printing out long messages.

dwks
04-11-2007, 04:12 PM
Me too, for multiple lines usually. Sometimes I run into a GCC error message to the effect of "string length is longer than the C89 standard of 509 characters". I think that's for 509 chars + 1 NULL + 2 chars for string length to fit into 512 characters, but I'm just guessing.

brewbuck
04-11-2007, 04:15 PM
Me too, for multiple lines usually. Sometimes I run into a GCC error message to the effect of "string length is longer than the C89 standard of 509 characters". I think that's for 509 chars + 1 NULL + 2 chars for string length to fit into 512 characters, but I'm just guessing.

I have a vague recollection of reading somewhere that the choice of 509 was actually a typo in the original standard, which wasn't considered important enough to fix. But take that with a truck-sized grain of salt.

Dave_Sinkula
04-11-2007, 06:35 PM
x[0]=0;
y[0]=0;

for(i=0;i<N-1;i++)
{
if(x[i]<1) x[i+1]=x[i]+Vx*dt;
else x[i+1]=x[i]-Vx*dt;

Help! I want the coordinates x[i] change from 0 over +1 to -1 and back as often as i<N. The program counts from 0 up to 1 - O.K. - but then oscillates from 1 to 0.9 and so on.Have you considered a lookup-table type of thing for the x[]?

#include <stdio.h>

double foo(int i)
{
static const double a[] =
{
+0.0,+0.1,+0.2,+0.3,+0.4,+0.5,+0.6,+0.7,+0.8,+0.9,
+1.0,+0.9,+0.8,+0.7,+0.6,+0.5,+0.4,+0.3,+0.2,+0.1,
+0.0,-0.1,-0.2,-0.3,-0.4,-0.5,-0.6,-0.7,-0.8,-0.9,
-1.0,-0.9,-0.8,-0.7,-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,
};
return a[i % (sizeof a / sizeof *a)];
}

int main(void)
{
int i;
for ( i = 0; i < 1000; ++i )
{
printf("%4g%c", foo(i), i % 10 == 9 ? '\n' : ' ');
}
return 0;
}

IsmAvatar2
04-12-2007, 10:39 AM
Actually that's what I was suggesting with the memoization, but figured it wasn't worth it since the lookup table would be 40 elements. Plus I was using an algorithm to generate the lookup table, which I realized I could just bypass the lookup table and just use that algorithm to calculate the values themselves by modulating them over 40.

What's the "static" do when you say "static const double a[]"? I'm familiar with static from Java, but have never seen it used in my short time with C, since C isn't object oriented, and static from Java is an object-oriented term.

brewbuck
04-12-2007, 10:43 AM
What's the "static" do when you say "static const double a[]"? I'm familiar with static from Java, but have never seen it used in my short time with C, since C isn't object oriented, and static from Java is an object-oriented term.

The static causes the array to be allocated statically (like global variables) instead of on the stack. If it were on the stack, the program would have to copy the contents of the array into a new array on the stack for every single call to the lookup function. But because it is static, the array "just exists" and the function refers to it without having to construct it.

EDIT: In this case, it means pretty much the same thing as "static" in Java -- the data belongs to the "class" (running program) instead of the "instance" (function invocation). The "static" keyword was taken from C for use in Java, so it's no surprise the idea is similar.

If something is a static global variable, it means something slightly different -- the global variable is exactly like any other module-level variable (e.g. globals) but it cannot be referenced outside the module it is declared in. So "static" means two different things in C.

dwks
04-12-2007, 03:03 PM
If something is a static global variable, it means something slightly different -- the global variable is exactly like any other module-level variable (e.g. globals) but it cannot be referenced outside the module it is declared in. So "static" means two different things in C.
You can also declare static functions, which can only be referenced from within the source file. This is useful for large projects because it's like rudimentary namespaces.