views:

86

answers:

3

Assume we have an integer 'x' and 'n' possible values that 'x' can be mapped/binned to. What is an elegant way in C to have a function that returns the closest 'nth' value to x?

Pseudo code example;

int x = 40;
int res;
int bins[] = { 0, 20, 80, 200 }; /* Sorting is guaranteed */

res = int_bin(x, bins);
assert(res == 20); /* 40 is closer to 20 than 80 */

x = 150;

res = int_bin(x, bins);
assert(res == 200); /* 150 is closer to 200 than 80 */

By elegant I mean not just a bunch of if/else if/else statements.

+5  A: 

If the list is sorted, then you can simply do a binary search for the value.

If the search does not find the value in the list, you will know at what index the value would have been located had it been in the list. Then, you can then compare the value against the element at that index and the element at the previous index (if the index isn't zero, obviously) and see which is closer.

James McNellis
A: 

Answering my own question here.

Since I'd like to reuse as much standard C functions as possible. I don't believe I can use bsearch() because that will give me no information as to the index of where the element should go if not found; I'd need to roll my own.

However, what about using qsort() on the bins[] array and give a comparison function that sorts based on how close the bin is to 'x' and then choosing the 0'th element as my answer?

SiegeX
@SiegeX: Right; if the value isn't found, `bsearch()` will return a null pointer. You probably don't want to take the `qsort()` approach because that would have nlogn complexity, whereas a straightforward binary search would have logn time complexity (and do you really want to have to keep resorting the array?). The approach I describe should be implementable in 15 or 20 lines of code. It'll take a bit of testing, but shouldn't be too difficult.
James McNellis
In the future, you can just add this information to the original question. That makes the content easier to follow on the page.
James McNellis
the last thing sounds like a generic solution SiegeX, but you don't need a sort function that is O(N log N), you only need a minimum function with the same sorting key =abs(bin - x), and that algorithm is only O(N)
kaizer.se
+1  A: 

Instead of storing the central value of each bin, store the boundary values around each bin. Use sentinel values at the beginning and end of the array to ensure that a search always finds an answer. In your example, replace { 0, 20, 80, 200 } with { INT_MIN, 10, 50, 140, INT_MAX }.

You can use a linear search if the real problem is as simple as your example. Otherwise, a binary search is the way to go.

Judge Maygarden