The best way to implement piece-wise periodic function in Objective-C?
I need to implement kind of illustrated function ( ratio = somefunction(time)) in Objective-c. Language doesn't actually matters, because task seems purely algorithmic. Is there any common way to do things l开发者_StackOverflow社区ike this? Next things should be easily adjustable in process of design:
1) Number of small intervals per period (now it 4, but it can be 3 or 20 for example). 2) f1 can be changed. It's simple function like f(x) = sin(x). 3) if we say
f_resulting =
f1 for a time t1
f2 for a time t2
then again
f1 for a time t1
etc..
ratio when f1 "works" vs f2 "works" (t1 to t2) should be adjustable.
Standard C itself has no closures so if you use C function pointers you need to build your own closure - you just use a class instance to store the two function pointers and duration and an invoke method to call the composed periodic function.
However Apple has introduced blocks, which are just inline functions implemented with closures, so in Apple C you can easily compose functions. This is more interesting, but "best" you will have to decide...
An example which composes double -> double functions. First the header, Periodic.h:
typedef double (^Monadic)(double);
Monadic makePeriodic(Monadic firstFunction, double firstPeriod,
Monadic secondFunction, double secondPeriod);
And the implementation, Periodic.c:
#include "Periodic.h"
Monadic makePeriodic(Monadic firstFunction, double firstPeriod,
Monadic secondFunction, double secondPeriod)
{
return Block_copy(^(double time)
{
return fmod(time, firstPeriod+secondPeriod) < firstPeriod
? firstFunction(time)
: secondFunction(time);
}
);
}
Blocks are constructed on the stack and can reference local variables and parameters in the enclosing scope. As such you cannot simply return a block from a function as the scope it refers to disappears on return. The function Block_copy()
moves a block, and any blocks it refers to, onto the heap allowing them to outlive their creating scope. A heap block must be released with Block_release()
when no longer needed.
And a simple demo:
Monadic queer = makePeriodic(^(double t) { return t * t; }, 5,
^(double t) { return sqrt(t); }, 3);
for(double ix = 0; ix <= 16; ix++)
printf("%f -> %f\n", ix, queer(ix));
Block_release(queer); // clean up
Now you can wrap all this up in a class if you wish so it fits Obj-C style. When you do this you can also send copy
and release
messages to the block, just as if it was an Obj-C object. In a garbage collected environment you still need the copy
to get thge block onto the heap, but the release
is not needed.
Periodic.h:
typedef double (^Monadic)(double);
@interface ComposeOne : NSObject
{
}
+ (Monadic) makePeriodicWithFunction:(Monadic)firstFunction
forPeriod:(double)firstPeriod
andFunction:(Monadic)secondFunction
forPeriod:(double)secondPeriod;
@end
Periodic.M:
@implementation ComposeOne
+ (Monadic) makePeriodicWithFunction:(Monadic)firstFunction
forPeriod:(double)firstPeriod
andFunction:(Monadic)secondFunction
forPeriod:(double)secondPeriod
{
Monadic result = (^(double time)
{
return fmod(time, firstPeriod+secondPeriod) < firstPeriod
? firstFunction(time)
: secondFunction(time);
}
);
return [result copy];
}
@end
And the simple demo (still using printf though for convenience):
Monadic queer = [ComposeOne makePeriodicWithFunction:^(double t) { return t * t; }
forPeriod:5
andFunction:^(double t) { return sqrt(t); }
forPeriod:3];
for(double ix = 0; ix <= 16; ix++)
printf("%f -> %f\n", ix, queer(ix));
[queer release];
精彩评论