5

I want to use Brents method as present in the Numerical Recepies Book to minimize a function. The signature of the minimzation routine essentially looks like this:

float brent(float (*f)(float), float *xmin, "other parameters not relevant to question")

As you can guess brent returns the minimum value of f and stores its argument in xmin. However, the exact form of the function I want to minimize depends on additional parameters. Say

float minimize_me(float x, float a, float b)

Once I decided on the values of a and b I want to minimize it with respect to x.

I could simply add additional arguments to all functions called, all the way down to brent, thus changing its signature to

float brent(float (*f)(float,float,float),float a ,float b , float *xmin, ...)

and consequently call (*f)(x,a,b) inside brent every time. This, however, seems not really elegant to me since I would now have to pass not only the pointer to minimize_me, but also two additional parameters down a whole chain of functions.

I suspect there could be a more elegant solution, like creating a pointer to a version of the function with a and b as fixed values.

Even if it is a really obscure solution, please don't keep it from me, since I feel it could improve my overall understanding of the language.

DavidH
  • 415
  • 4
  • 21
cmmnn
  • 315
  • 3
  • 10
  • maybe you're looking for this? https://stackoverflow.com/questions/7308449/how-to-use-varargs-in-conjunction-with-function-pointers-in-c-on-win64 – kenny Feb 16 '18 at 13:40
  • 1
    you might consider creating a struct with your parameters and pass its pointer to the function – Nefrin Feb 16 '18 at 13:40
  • @Nefrin something like `typedef struct { float a; float b; float (*f)(double,double,double) } f_ab;`? Am I getting this right? I am not that used to c yet. – cmmnn Feb 16 '18 at 13:49
  • 1
    yes @cmmnn, you can then create an instance with `f_ab myAB` set its values and pass its pointer into a `function(void* param)` with `function(&myAB)` and then cast it back to the `f_ab` type. This method alows passing structs with arbitrary content to a function with a single parameter – Nefrin Feb 16 '18 at 14:00
  • ok I´ll consolidate this in an answer – Nefrin Feb 16 '18 at 14:03
  • there's a gcc extension called local functions and similar thing exists in clang (with different syntax). What's your compiler? – Uprooted Feb 16 '18 at 14:25
  • @user7231 gcc, so this could be helpful. From an idealists standpoint I would prefer a solution independent of the compiler. – cmmnn Feb 16 '18 at 14:28

3 Answers3

6

A viable way of achieving this is to use a struct to store all the values and pass a pointer to that to the function.

struct parameters{
    int valueA;
    int valueB;
};

int function(void* params){
    parameters* data = (parameters*) params;
    return data->valueA + data->valueB; // just an example
}

int main(){
    parameters myData;
    myData.valueA = 4;
    myData.valueB = 2;
    function(&myData);
    return 0;
}
Nefrin
  • 338
  • 3
  • 11
  • Nice answer +1...one small thing I want to ask you..that casting is mandatory? Just asking. – user2736738 Feb 16 '18 at 14:34
  • `void* params` is not type safe. It would be better to use argument type `struct parameters * params`. – user694733 Feb 16 '18 at 14:35
  • yes, casting is mandatory. otherwise the compiler does not know how big the structure is and what values it contains. (although you could do the pointer arithmetic yourself) – Nefrin Feb 16 '18 at 14:37
  • Also, small nitpick: `(parameters*)` wont compile, because only type `struct parameters` exists. And cast is not even necessary as `void*` can be implicitly converted to any other object pointer type. Compiler doesn't need to know the size of pointed structure. – user694733 Feb 16 '18 at 14:37
  • 1
    The idea of using a pointer to struct, I have found, is so useful in so many ways, but sadly under utilized. Nice answer! – ryyker Feb 16 '18 at 14:40
5

What you need is currying, say for example:

given a function of three variables f(x,y,z) and two values a and b, construct the function g of one variable such that g(z)=f(a,b,z).

Alas C language is not able to let you currying. Such a construction is available to functional languages only and C is not one. This doesn't mean that you really can't do it, but there is no given construction for it in the language. So you need to reconstruct the mechanism by yourself. See Currying/binding with ISO C99 or Is there a way to do currying in C? for examples.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • Jean nice answer(+1) but would you mind in single line explaining currying...many will be too lazy to open link from answer. (Or manybe it is not that common a topic). – user2736738 Feb 16 '18 at 14:34
  • I've had to do such things in C, but never knew such well developed and formalized thoughts existed, or were even named. – ryyker Feb 16 '18 at 14:35
  • @ryyker well CS is...a **science**. So there exists a lot of theorems and alike in the field. – Jean-Baptiste Yunès Feb 16 '18 at 15:06
  • 1
    @Jean-BaptisteYunès - Lol, yes, I suppose so. Being one not formally educated in that field, I fear I have missed out on some very cool stuff. However, that fact also means I have a great appreciation for said cool stuff when I run into it here. :) – ryyker Feb 16 '18 at 15:57
1

GCC's local functions extension is a pure joy to use (use -std=gnu11):

float brent(float (*f)(float), float *xmin);

float minimize_me(float x, float a, float b);

int main() {
   ...
   float min_me_local(float x) { return minimize_me(x, 1, 2); }
   brent(min_me_local, xmin);
   ...
}

I wish it was standard, but it isn't. So prefer answer from @Nefrin when aiming at portability.

Uprooted
  • 941
  • 8
  • 21