I'm looking for an efficient algorithm that clamps an integer value within a range, while also changing its base10 end to one of multiple, variable length ends.
This should clamp a value
between the min
and max
, while changing the end to one of the specific ends defined in ends
, as close as possible to the original value.
Example input data:
ends: [26, 201, 330] (sorted list of integers, at least a factor 10 smaller than <value>)
min: 5350
max: 7392
value: 2000
-> 5426
value: 6205
-> 6201
value: 7400
-> 7330
I'll implement this in Go, but any pseudocode or other imperative language is also appreciated.
I guess you know how to clamp:
clamp(n, min, max) = max(min, min(max, n))
Then to remove the end and replace it with what it should end, you need the next higher power of 10:
nextPowerOf10(n) {
if (n == 0)
return 10 // mathematically not correct but works here
x = 1
while (n > 0) {
x = x * 10
n = n / 10 // integer division
}
return x
}
So replacing the end of a number becomes simple:
replace(n, end) = n - n % nextPowerOf10(end) + end
Then you can check the other candidates on both sides, so when m = replace(clamp(n, min, max), end)
and p = nextPowerOf10(end)
, the other candidates are: m - p
and m + p
, everything put together:
clampEnd(n, min, max, end) {
m = clamp(n, min, max)
p = nextPowerOf10(end)
m = m - m % p + end
diff = -1
ret = -1
for (x in [m - p, m, m + p]) {
// this rounds down, make abs(n - x) <= diff to round up on equal distance
if (x >= min && x <= max && (diff < 0 || abs(n - x) < diff)) {
diff = abs(n - x)
ret = x
}
}
return ret // returns -1 if no number in range ends with end
}
Examples: