C++ Callback Benchmarks

March 10th, 2010

I did a little optimization on my callback library, PlusCallback, and decided to do some benchmarks.

Speed wasn’t really a consideration in PlusCallback’s design; simplicity was. Still it ends up being about twice as fast as Boost.Function. I believe this is because PlusCallback takes a straightforward approach to solving the method callback problem. Boost.Function takes a much more roundabout approach, which gives it its flexibility. In fact, Boost.Function doesn’t even directly support method callbacks on instantiated objects. Boost.Function method callbacks only work in combination with Boost.Bind or the standard binding functions (e.g. std::bind1st).

Here is a graph of the results, for what they’re worth. The values are in millions of iterations per second, so more is better.

Boost has several intermediary steps to invoking a method callback:

0) Actual Method Being Called
1) std::mem_fun1_t::operator()
2) std::binder1st::operator()
3) boost::detail::function::function_obj_invoker1::invoke
4) boost::function1::operator()

PlusCallback really only has one behind the scenes step:

0) Actual Method Being Called
1) cb::Callback1::ChildMethod::operator()
2) cb::Callback1::operator()

Again, this reflects different design goals. PlusCallback achieves one goal directly. Boost.Function stays flexible and is more of a building block.

The benchmark code is included in the latest PlusCallback download. If you get different results, please let me know.

C++ Callback Comparisons

March 8th, 2010

Today I’m going to do a quick comparison of C++ callback choices. I’ll look at C++’s native support for callbacks, as well as Boost, and PlusCallback. I wrote PlusCallback, so I’m obviously quite biased, but I’m going to demonstrate with actual code and can hopefully make a compelling case anyway.

First, we’ll define two functions to work with, one method and one plain free function. Both functions have the same signature: int return type, and one int parameter.

struct X {
    int Foo(int a);
};
 
int FreeFoo(int a);

Now, using C++’s native method pointers, we can construct a callback for the Foo method.

X x;
 
//The method pointer and object pointer are stored separately.
int (X::*callback)(int) = &X::Foo;
X* object = &x;
 
//Call x.foo(5). Note use of rare ->* operator.
(object->*callback)(5);

Of course, this callback pointer can only ever point to a method in the struct X. You can’t re-point it to a method in another class, and you can’t re-point it to a free function. This makes it worthless for any callback functionality because the caller would have to know what it’s going to call at compile time. If this information is available at compile time, you obviously don’t need callbacks. Other drawbacks include the need to store the function pointer and object pointer separately, a complex syntax, and almost no run-time flexibility.

As a side note, ->* is called the “Bind pointer to member by pointer” operator. And yes, you can overload it.


Boost provides function pointers that are oceans better.

X x;
 
//Setup callback for x.foo. Note complexity for simple task.
boost::function<int (int)> callback = std::bind1st(std::mem_fun(&X::Foo), &x);
 
callback(5); //Call x.foo(5);
 
//Change callback to free function.
callback = FreeFoo;
 
//Call FreeFunction(8).
callback(8);
 
//Boost doesn't support the < operator for function callbacks.
//assert(!(callback < callback));

boost::function isn’t too bad. It can be reset to any object or free function at run-time. The drawbacks are a huge library dependency and a complicated syntax. Also, boost::function objects can’t be sorted or stored in containers that require a sort order (like std::set and std::map).

Fun fact: the C++ preprocessor expands

#include <boost/function.hpp>

into over 30,000 lines of code.


PlusCallback supports all these features with a simple syntax.

X x;
 
//Setup callback for x.foo.
cb::Callback1<int, int> callback(&x, &X::Foo);
 
//Call x.foo(5).
callback(5);
 
//Change callback to free function.
callback = FreeFoo;
 
//Call FreeFunction(8).
callback(8);
 
//The < operator works fine.
//One can safely store these callbacks in a set or map container.
assert(!(callback < callback));

PlusCallback is contained in a single header file. It doesn’t drag any dependencies into your project, and it doesn’t need compiling. It uses the zlib license, and can be used in commercial applications freely.

PlusCallback 1.3 Released

March 6th, 2010

I wrote a library a while back implementing easy to use C++ callbacks called PlusCallback. The library is contained in one header file (with nothing to compile) and has the easiest syntax I’ve ever seen for this sort of thing. I am releasing it to the public under the zlib license.

Head over here for a quick overview.

Any comments are greatly appreciated.

Optimal Bit Packing

November 21st, 2009

I recently ran into a problem where several values had to be stored in an very minimal amount of space. As an example, we will use four values. Let’s call these values bitpack_a, bitpack_b, bitpack_c, and bitpack_d. Each value has a well defined range, such as:

bitpack_limits

Suppose now, that we want to encode all four values into one number. Furthermore, we want to minimize the bandwidth or space this value requires.

Most C programmers know (or at least should know) about bit fields. Bit fields allow a C programmer to set the number of bits required for each integer. For example:

union Pack
{
    unsigned int code;
    struct
    {
        unsigned int a : 5;
        unsigned int b : 7;
        unsigned int c : 9;
        unsigned int d : 11;
    } packed;
};

Using this method, we can encode all four values into 32 bits. This will greatly reduce the size over the naive method of using a plain int for each value.

bitpack_pack

The problem here is that each value is actually taking up more space than is absolutely required. For example, we know from our requirements that bitpack_a will always be less than 18. Yet, using bit fields we must assign at least 5 bits, which means we could store a value as high as 31. This is wasted space.

Why would anyone worry about wasting a fraction of a bit of memory? Bit packing is only useful when bandwidth or space is extremely limited. For example: applications where a user must key in a value (hopefully encoded in a high base, using letters and numbers). Remember how some old Nintendo games “saved” by having the user write down a string? With bit packing a few characters can be knocked off that string. Similar codes are still used for order processing, check sums, ect. Bit packing can also be useful for encoding information in bar codes.

Optimally packing bits involves only a slight change in the formula. The mathematical formula for our bit field looks like this:

bitpack_2math

It’s not hard to see that there is actually no reason to stay on power of 2 boundaries. To maximally pack the values we will simply rewrite the formula using our data’s actual boundaries, not arbitrary power of two numbers.

bitpack_maxmath

Packing and unpacking is still fairly straightforward in C.

unsigned int pack(unsigned int a, unsigned int b,
        unsigned int c, unsigned int d)
{
    unsigned int code = d;
    code *= 311;
    code += c;
    code *= 100;
    code += b;
    code *= 18;
    code += a;
    return code;
}
 
 
void unpack(unsigned int code,
        unsigned int& a, unsigned int& b,
        unsigned int& c, unsigned int& d)
{
    a = code % 18;
    code /= 18;
    b = code % 100;
    code /= 100;
    c = code % 311;
    code /= 311;
    d = code;
}

There you have it. What took 32 bits before can now fit in just 30 bits. That’s a savings of over 6%. Wow.

Like I mentioned above, that savings can quickly become substantial if there are many values, or if space is at an extreme premium.

Setting up a New Computer

November 14th, 2009

I recently upgraded to a new Core i7. Installing Windows Vista on a blank hand drive has given me a chance to think about my most commonly used software. I thought it may be interesting to make a list, and perhaps contrast again in a couple of years.

Here it is, organized by roughly how I organize my start menu.

Graphics

Blender – A great 3D modeling and rendering program. The learning curve is steep, but the interface is quite good once you’re used to it.
Gimp – Image editing software. It’s fairly easy to script in Scheme.

Math / Plotting

Gnuplot – Plotting software.
Graphviz – Graph visualization software. Useful for flow charts and other diagrams.
Maxima – Computer algebra system. Amazingly useful for anyone who uses math.

Programming

Ack – Text searching. It’s quite a bit better than grep, like the URL says.
CMake – A decent cross platform build system. I use this with most of my C and C++ projects.
Dependency Walker – Windows tool for listing dependencies. Don’t even think of publishing software with using this tool first. You’re forgetting a DLL. Yes you are.
Doxygen – Source code documentation tool.
OllyDbg – 32-bit assembler level analyzing debugger.
Strawberry Perl – Perl for Windows.
TortoiseSVN – A nice subversion client for Windows. It integrates nicely with Windows Explorer.
Vim – A great text editor. I use this for everything. Typing in any other editor only breeds contempt and frustration. Seriously.
MinGW and MSYS – C and C++ compilers for Windows. MinGW is a port of GCC. MSYS is useful for compiling free software using the GNU build system.

Utilities

7-zip – Compression software. It can be ran from the command line, so I also use it to automate backups.
ImgBurn – CD/DVD burning. I’d sooner stab my eyes out than use some of the commercial software available for this task.
UltraMon – If you run dual (or more) monitors, you need this software. It’s sad to think that Windows doesn’t include these features out of the box. This is the only software on this list that isn’t free.
QTTabBar – Adds tabs to Windows Explorer. Very useful. Unfortunately, it also seems a bit buggy from time to time.

So there it is. Not too exciting.

Introduction to Splines

September 19th, 2009

This is the second post in a multiple part series. The first post was on interpolation between two values. Here we will look at interpolation between multiple values.

Splines are mathematical functions to interpolate between several values. They are defined as piecewise polynomials, meaning that each interval is handled separately.

So, let’s get started. For example, we will interpolate with 10 control points. The interpolation function will loop, so we also copy the first point to the end. Also note that these control points are uniformly spaced (at 0, .1, .2, .3, etc) on the X axis. In general we will try to avoid having uniform spacing as an absolute requirement because it’s not always practical.
splines_1d_points

Our goal with a spline is to take in a list of inputs, Xs, and outputs, Ys, and produce a reasonable output for any given input. Each XY pair is called a control point, knot, or duck. The input into a spline function is usually labeled splines_t, for time.

Remember that splines are defined piecewise; a separate function can be written for each interval. The simplest spline uses the Step function for each interval. That is, it just jumps to the nearest control point. This is rarely useful, and mostly makes its way into programs by accident.
splines_1d_step

Next, we can use linear interpolation for each interval. Note that linear interpolation only considers the two surrounding control points for each interval. Because of this, it is very local. Any one control point only affects the interval immediately before and after it. We will also look at this spline’s derivative. You can easily see that it’s not continuous. If you prefer to think of the spline function as defining an object’s position, then the derivative can be thought of as the object’s speed. It not hard to imagine that linear interpolation gives a jerky appearance in animations, because of it’s non-continuous speed and infinite acceleration.
splines_1d_linearsplines_1d_linear_d

Cosine interpolation fixes the non-continuous derivative, but introduces other problems. It forces the derivative at each control point to be 0. So, if cosine interpolation is used in animation, an object will slow down and stop at each control point. This is usually undesirable, but it can nevertheless sometimes be useful. Cosine interpolation is still local, it only every considers the immediately adjacent control points for each interval.
splines_1d_cosinesplines_1d_cosine_dsplines_1d_cosine_dd

Cubic Hermite Splines

To get smoother interpolation it is desirable to consider more than just two control points for each interval. Natural cubic splines have global control, and the function always considers each control point. Catmull-Rom, Cardinal, and Kochanek-Bartels splines use four control points for each interval (that is the two immediately surrounding control points, and an extra control point on each side, for each interval). These last three splines are all types of cubic Hermite splines.

A cubic Hermite spline is a spline with each polynomial in Hermite form. Basically, each interval will use two control points and two tangents. These tangent values can be defined by the user, or defined automatically by more surrounding control points. First off, we need to define the four Hermite basis functions.

splines_h1_function

splines_h2_function

splines_h3_function

splines_h4_function

splines_hermite_basis

Each interval uses the four basis functions like so:
splines_hermite_function where splines_m1 and splines_m2 are the tangent values.

You can see that splines_h1 and splines_h2 scale the control points, while splines_h3 and splines_h4 scale the specified tangents. You can also quickly see that the spline will pass through each control point by considering the scaling factors from the graph above.

The tangents can be specified individually by an artist, or generated automatically. They are usually generated automatically, but to get a feel for the cubic Hermite spline I’ll show an example where every tangent has been specified as 1. You can see that the function always has a slope of 1 at each control point. In other words, it passes through each control point at 45 degrees because that was the tangent specified.
splines_1d_hermite

Cardinal Splines

Given the control points splines_y0, splines_y1, splines_y2, and splines_y3 we can use a Cardinal spline to interpolate between splines_y1 and splines_y2.

Assuming uniformly spaced control points, a Cardinal spline defines the tangents as:
splines_m1_function splines_m2_function
Where splines_c is a tension parameter. The tension parameter can intuitively be thought of as the length of the tangents. splines_s is a scaling factor for non-uniform control point spacing. If the control points are uniformly space, it can be omitted or set to 1. We’ll cover non-uniform control point spacing below.

Here are some examples of Cardinal splines with various splines_c (tension) values:

splines_1d_cardinal_lsplines_1d_cardinal_h

It’s straight forward to adapt the Cardinal spline for non-uniform control. However, it seems to be little known. A search online doesn’t turn up much help and indeed a few sources even say it’s non-trivial or even impossible (due to the curvature of the curves, uh-huh). That’s not true. Using non-uniformly spaced control points is actually quite straightforward.

For non-uniform control points, each tangent simply needs scaled. First we’ll define a few variables useful for the control point spacing.

splines_dx_function splines_dx1_function splines_dx2_function

Then the scaling factors are:
splines_s1_function splines_s2_function

Non-uniform control point spacing is incredibly useful for animation key-framing. With uniform control points an artist would have to specify the models’ positions every fixed amount of time (e.g. every half second). With non-uniform control point spacing, an animation artist can specify models’ positions whenever convenient.

Catmull-Rom Splines

A Cardinal spline with a tension of .5 is a special case. It’s then called a Catmull-Rom spline. Catmull-Rom splines are thought to be esthetically pleasing and are quite common.
splines_1d_catmullromsplines_1d_catmullrom_dsplines_1d_catmullrom_dd

Two Dimensional Splines

Wrapping up, we’ll take a quick look at two dimensional splines. It should first be noted that the X and Y axis can be interpolated completely separate. This makes sense since the axises are orthogonal, and a movement on one axis does not affect the other axis at all. Good spline code should be written generically and work equally well with a single number or a vector. In C++ this is easily accomplished with templates, which allows the same code to be used for one or more dimensions.

splines_2d_linear
splines_2d_cardinal
splines_2d_catmullrom

Next up we’ll look at arc-length parametrization.

Game Scripting Languages

July 4th, 2009

Many games use scripting languages for animation and game play logic. This has the advantage of quick prototyping, and better organization of code. Almost every non-trivial game engine uses some scripting language.

There are many scripting languages suited to such a task. Lua is perhaps the most popular game scripting language. Other choices include: AngelScript, GameMonkey, Io, Pawn, Squirrel, and Scheme. Sometimes heavy-weight languages are also used, like Python or Ruby. These languages are usually quite a bit harder to embed, and aren’t know for their speed.

In this post I will compare AngelScript, GameMonkey, Pawn, Lua and Squirrel for my comparisons. I’ll also take a quick look at TinyScheme, although not run it through all the comparisons since it is interpreted. Io looks very interesting, but unfortunately it is severely lacking in documentation and won’t be compared here.

Language Introductions

Pawn is the odd one in the group, so we’ll start there.

Pawn (formally called Small) is small and simple. It uses a C like syntax and has only one data type, the cell. A cell is usually an integer, but it can also be treated as a character, boolean, or floating point value. Pawn has no support for structures or classes, but structures can be faked using named array positions.

Pawn is the only language in this roundup that completely separates its compiler from its virtual machine. It also, by far, has the most static compile time checks. All variables must be declared, and all native functions must have forward declarations. This is nice, because it alleviates run time checking on native function parameters. And of course, it’s much quicker to find an error at compile time than at run time. I found the compiler to also have very thorough warnings, for example it even warns about inconsistent indentation. My only grievance with the compiler, is that it requires leading zeros for floating point values. For example, it won’t accept .5 as a constant, but instead requires 0.5.

Pawn has very through documentation, has enjoyed some widespread use, and has an almost inactive forum. Pawn is the quickest and lightest scripting language I’ve seen. I’m using it for low level scripting in my game, including character and object animations.

Lua has its own unique syntax that’s a bit reminiscent of Basic (i.e. no curly brackets). It’s also very fast and compiles into fairly small byte-code. It’s very dynamic, variables don’t need to be declared before use, and functions are first class values (meaning that the compiler and abstract machine are very tightly coupled, and functions can be stored in variables). Lua makes extensive use of tables (associative arrays), which are its only complex data type. Tables are able to mimic classes and objects, by using some entries to store functions (first class value, remember) and some entries to store data.

Lua has been used extensively in the industry, has an active online community, and a large base of open source modules. Lua has predated and influenced every other language in this roundup. I found that Lua’s reference API documentation seems a bit vague until you get the hang of it (but there are many examples that make up for it). Lua also has a book available, Programming in Lua, that covers both the language itself and embedding, in detail.

GameMonkey borrows some concepts from Lua, but uses a C like syntax. It makes heavy use of tables, and can fake objects using tables the same way as Lua. It has finite state machine support, variables don’t need to be declared, and functions are first class values.

GameMonkey’s speed and small byte-code size really surprised me (it’s lean and mean). However, its API reference documentation is quite lacking. The source code is commented with Doxygen statements so running Doxygen helps (I couldn’t find a distribution of the generated reference online). It comes with a remote script debugger. I only played around with debugging briefly, but it’s quite neat.

There doesn’t seem to be a lot of hype surrounding GameMonkey, but they do have an active forum. Several community members seem to contribute back to GameMonkey, community contributions include many bindings, an even better debugger, etc.

Squirrel is a high level dynamically typed object oriented language support classes and inheritance with C like syntax. It also borrows tables from Lua. It was very easy to compile (one makefile) and seems to have top notch documentation.

Although Squirrel is still young, it has already been used in some commercial applications and has an active online forum.

AngelScript is a statically typed language with a C++ like syntax and classes. AngelScript has the best native binding in the bunch. Usually, a function or class only needs to be registered with the AngelScript virtual machine to be usable by a script. All the other languages in this roundup require intermediate helper functions for binding. However, the scripts cannot be compiled unless each native function is first registered. This adds an extra step to anyone wanting to ship pre-compiled AngelScript byte-code.

AngelScript doesn’t support tables, and in fact they wouldn’t be terrible useful because of AngelScript’s static typing.

AngelScript has an active online forum, pretty good documentation, and seems to be updated often.

TinyScheme is also worth a mention. It is contained in one C source file. Unlike the other languages in this review, it is interpreted, and so is about an order or two of magnitude slower. However, if speed isn’t an issue and you just want to easily add Scheme to your project, I would highly recommend it.

I tried some other schemes, but always had trouble compiling. TinyScheme is easy to compile, has many options, and is easily hackable.

Version Tested and Licenses

Language Version License
AngelScript 2.16.0 zlib
GameMonkey 1.25 MIT
Lua 5.1.4 MIT
Pawn 3.3.4058 zlib
Squirrel 2.2.2 zlib
TinyScheme 1.39 BSD

Binding

Embedded scripting languages are useless without being able to call native C functions or C++ methods. AngelScript easily wins here, just tell the library about your function and it’s instantly available to the script. The other languages need some glue code.

Pawn passes its function parameters as an array of ints. Floats simply need a cast, but for strings you’ll need to call a couple special functions first.

GameMonkey, Lua, and Squirrel use a stack to pass parameters. Because they are dynamic languages, values can be popped off the stack as different types (e.g. int, float, char*). The idea is a bit tricky to grasp, but it works quite well once you get the hang of it. Each language defines several macros to make using the stack a bit less verbose.

Each library also has third party libraries available to make binding easier. For example, here is a list of binding libraries for Lua. Personally, I feel you’re better off using native bindings, maybe with some custom macros. I question the reasoning behind wanting to use a bloated template binding library to expose your whole engine to a scripting language automatically.

Concurrency

AngelScript, Lua, GameMonkey, and Squirrel all support some form of concurrency. This allows scripts to create threads that appear to run parallel in the virtual machine. This is useful for when a script needs to run a long algorithm without disrupting its other responsibilities. These threads don’t give a performance advantage, but rather a programming advantage.

GameMonkey has native support for blocking threads until another event happens. For example, if one thread needs to wait for a door to open, it can go to sleep until another thread throws a “door open” event. I don’t think this would be hard to add with the other languages, but it’s nice that GameMonkey already has it.

Speed

I did a few speed tests in each language. These tests in no way reflect actual real world scripts, but they should give a comparison of each language’s basic overhead. The Fibonacci test tests function call overhead, by having a script function calls itself recursively 1,402,817,464 times. The prime test implements repeated iteration and basic integer math. The native string tests has the script call a native (C or C++) function ten million times while passing a 12 character string argument. The native number tests calls a native function a billion times while passing a single numeric parameter. Lua only supports doubles, but the other languages are tested by passing an integer type variable.

script_time

Each test was first compiled to byte-code, so the test time includes loading byte-code from disk, but it does not include compiling times for any language. Pawn, Lua, and Squirrel come with stand-alone compilers. AngelScript and GameMonkey use byte-code, but I had to actually throw together programs to save compiled scripts (which wasn’t a huge deal in either case).

It’s worth mentioning that Lua, Pawn, and Squirrel have Just-In-Time (JIT) compilers available. I didn’t test any of them. Pawn comes with a pre-compiled assembly implementation, so I did test it.

Since scripting languages are often used for string processing, I also bench-marked a script passing variable length strings to native functions. Pawn represents strings in a special way inside of its virtual machine, and it can be costly to convert longer strings. The other languages don’t need any special conversion, and so have a relatively constant speed regardless of the string’s length.

script_native_strings

Byte-Code Size

It’s likely that a published game may distribute compiled byte-code instead of source code scripts. Each tested language produces fairly small byte-code, which makes most of these suitable for use as simple configuration scripts. In many cases, the size and speed may be less costly than traditional configuration files, like XML (which wasn’t designed for that purpose either).

script_size

Library Size

This is probably rarely an actual issue, but these are the virtual machine library sizes. In others words, if you want your program to run scripts, expect your executable to bloat by this amount.

script_lib_size

Syntax

I’m including the scripting code used in the benchmarks here. The tests should give you a basic feel for each languages’ syntax.

AngelScript, GameMonkey, Pawn, and Squirrel each use a C like syntax with brackets. Lua has its own syntax, which works quite well. Non-programmers may find Lua’s syntax easier.

With the excepting of scheme (.scm), I feel that the syntaxes are basically interchangeable. If you know C, should you should be able to learn 90% of the syntax for any of these languages in ten minutes.

Conclusion

Each language has its own strengths and weaknesses. If you need an embeddable scripting language, I hope this post gave you a bit of a head start.

I tried to be as fair as possible, but I’m sure I made mistakes. Any comments/suggestions/corrections are welcome.

Simple Interpolation

June 27th, 2009

This is the first of a multiple part series I’m doing on interpolation and spline functions. This post focuses on the simplest interpolation functions, which provide a smooth transition between (only) two values. I’ll provide generic C++ source code at the end of the series.

An interpolation function defines how a variable changes between two values (e.g. starting and ending position of an object) with respect to a third value (e.g. time). A spline allows smooth interpolation between an arbitrary number of control points, by defining a separate function for the interval between each control point. Splines are also very useful for drawing curves. Splines will be discussed in detail in the next post.

This post is going to focus on interpolating between two values. These simple interpolation functions can help polish any changing variable. Objects with changing position, rotation, scale, skew, color, or opacity can benefit from a smooth transition defined by simple interpolation.

The most basic interpolation function is the step function. It just jumps from one value to the next halfway through.interp_step_function

Nobody really uses the Step function on purpose. Instead, it shows up accidentally everywhere an unpolished transition is made. Whenever a programmer instantly repositions an object on the screen, he accidentally used the step function. If a game character gets hit, and his health bar display instantly updates, the Step function strikes again.

The simplest real interpolation function is Linear interpolation, also known as Lerp. It transitions from one value to another at a constant rate, using a straightforward and intuitive formula. The downside is its infinite acceleration and deceleration. When Linear interpolation is used to control movement or rotational speed, it has a tendency to look jerky. Still, it’s a huge leap better than the Step function.

interp_linear_function

Smooth Interpolation

So we need to modify the Linear function to provide a smooth acceleration and deceleration. An obvious way of doing this is to scale t using a smooth function. Cosine is a suitably smooth function.splines_interp_cosine

We only need to take the first half period, so our Cosine based interpolation function looks like:

interp_cosine_function

You can see Linear and Cosine interpolation compared in the animation below. The triangle on the left has a jerky start and end, while the Cosine interpolated rotation on the right has a smooth start and end.

splines_interp_rot_anim

A nearly identical polynomial function can also be constructed. It is called SmoothStep. In some applications it may be more efficient than calculating Cosine.

interp_smoothstep_function

Either Cosine or SmoothStep interpolation can replace almost all Linear interpolation for a smoother, more polished result.

I’d like to note just two more interpolation functions: Acceleration and Deceleration.

interp_acc_function
interp_decel_function

These functions are mainly useful for moving objects into or out of view. Acceleration can be useful for moving an object smoothly off the screen, because it has a sharp stop, but smooth start.

Visualizations

Here are three more comparisons: color interpolation, position interpolation, and a graph of the discussed functions.

splines_interp_grad

splines_interp_trans_anim

splines_interp

In the next post, interpolation functions will be combined over several points to create splines.