Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Passing values from structure arrays to a generic geometrical mean function Date: Fri, 27 Jan 2017 11:49:32 -0800 Organization: None to speak of Lines: 115 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: mx02.eternal-september.org; posting-host="7ccb5db651c5d414defb0728956f1471"; logging-data="9836"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19mS4FCsO4En/QQQVcyDX6v" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:H8XCv0NxZW0NUdhzl9cxRhAKyAQ= sha1:nkBtyQXxCDEY8VwrOKGR6KUiieI= Xref: csiph.com comp.lang.c:102592 Alla _ writes: > I have written (have not yet run it by compiler, so it is still > a theoretical, on-paper function) a geomean function. I would > like it to be a generic one, so it could be suitable for other programs > as well. (This function calls another geomean function, which > compute geomean for only two numbers.) > I am not sure I can write such a generic function, given > the specifics of my task. I still hope to find the solution myself, > but, if it is possible to write such a function given my spec, I will > be grateful for a hint from you (not a solution): > > double geomean(income_ptr->dip_amor, ba_ptr->gross_ppe, ba_ptr->intang) > { > double multiply = 0.0; > double gm = 0.0; > for (int i = 1; i < DATA_SIZE; i++) > { > multiply *= (1 + (income_ptr[i].dep_amor)/(geomean_twonums(ba_ptr[i-1].gross_ppe, ba_ptr[i].gross_ppe) + geomean_twonums(ba_ptr[i-1].intang, ba_ptr[i].intang)) ); > } > gm = pow(multiply, (1/DATA_SIZE)); > > return gm; > } Let me try to summarize what I *think* you're trying to do. (I haven't been following this thread 100% thoroughly, so I might be either repeating or misunderstanding some of what's been said.) You have an array of structures, where each structure has a member of type double. You want to compute the geometric mean of those N members. That seems straightforward enough that I don't mind showing a solution rather than a hint: #include #include struct foo { double x; }; static double geomean(struct foo *arr, size_t count) { double product = 1.0; for (size_t i = 0; i < count; i ++) { product *= arr[i].x; } return pow(product, 1.0/count); } int main(void) { struct foo the_array[] = { { .x = 3.0 }, { .x = 4.0 }, { .x = 5.0 } }; printf("Geometric mean = %f\n", geomean(the_array, sizeof the_array / sizeof the_array[0])); } Output: Geometric mean = 3.914868 (which is consistent with my manual calculation of the cube root of 3*4*5). You say you want to make the function "generic". That can mean a lot of things, but I think what you want is to have a function that can do the same thing for an array of *any* structure type that contains a double member. There is no clean way to do that in C. I can think of several not-so-clean solutions. The standard qsort() function gives some hints about how you can operate on arrays of arbitrary element types You could pass a void* pointer to the initial element of the array, along with a size_t indicating the size of a single element, another size_t to specify the number of elements, *and* yet another size_t to specify the offset of the double member within the structure. The body of the function will have to do some fairly ugly pointer casts to extract the actual data. If you do everything correctly, it should work, but there are a number of mistakes you could make that the compiler can't help you diagnose, because you you have to throw away type information. You could also wrap the entire function definition in a macro definition, with macro parameters to specify the name of the structure type and of the double member. You'd have to invoke the macro for each structure type, creating a new function with a distinct name. Or the geomean() function could take a function pointer as an argument, where the pointed-to function returns the value of the double member. But you'd still have to use void* pointers to refer to the array elements. The fact that doing this is so ugly might suggest that a change of data structure would be appropriate. (Or conceivably a change of language, but I'm not sure what language would handle this gracefully; I don't think C++ would.) If you're doing a lot of operations that have to iterate over sequences of double values, it's going to be a lot easier if they're stored in arrays of doubles, rather than scattered as double members of arrays of structures. On the other hand, that loses the coherence of using a structure to collect all the relevant information about a given entity in one place. Conceivably the structure could contain a pointer to the array element, but keeping that consistent is going to be non-trivial. -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"