def at(point, &block)
      # obvious cases first
      if @sorted.empty?
        # no key points
        return nil
      elsif @sorted.size == 1
        # one key point
        return @sorted.first.last
      end

      # out-of-bounds cases next
      if point <= @min_point
        # lower than lowest key point
        return @sorted.first.last
      elsif point >= @max_point
        # higher than highest key point
        return @sorted.last.last
      end

      # binary search to find the right interpolation key point/value interval
      left = 0
      right = @sorted.length - 2 # highest point will be included
      low_point = nil
      low_value = nil
      high_point = nil
      high_value = nil

      while left <= right
        middle = (right - left) / 2 + left

        (low_point, low_value) = @sorted[middle]
        (high_point, high_value) = @sorted[middle + 1]

        break if low_point <= point and point <= high_point

        if point < low_point
          right = middle - 1
        else
          left = middle + 1
        end
      end

      # determine the balance ratio
      span = high_point - low_point
      balance = (point.to_f - low_point) / span

      # choose and call the blending function
      blend = block || @blend_with || DEFAULT_BLEND
      blend.call(low_value, high_value, balance)
    end
def at(point, &block)
      # obvious cases first
      if @sorted.empty?
        # no key points
        return nil
      elsif @sorted.size == 1
        # one key point
        return @sorted.first.last
      end

      # out-of-bounds cases next
      if point <= @min_point
        # lower than lowest key point
        return @sorted.first.last
      elsif point >= @max_point
        # higher than highest key point
        return @sorted.last.last
      end

      # binary search to find the right interpolation key point/value interval
      left = 0
      right = @sorted.length - 2 # highest point will be included
      low_point = nil
      low_value = nil
      high_point = nil
      high_value = nil

      while left <= right
        middle = (right - left) / 2 + left

        (low_point, low_value) = @sorted[middle]
        (high_point, high_value) = @sorted[middle + 1]

        break if low_point <= point and point <= high_point

        if point < low_point
          right = middle - 1
        else
          left = middle + 1
        end
      end

      # determine the balance ratio
      span = high_point - low_point
      balance = (point.to_f - low_point) / span

      # choose and call the blending function
      blend = block || @blend_with || DEFAULT_BLEND
      blend.call(low_value, high_value, balance)
    end
returns the interpolated value at the Numeric point specified, optionally
 using a given block as the blending function

 if no key points have been specified, the return value is +nil+

 if one key point has been specified, the return value is the value
 of that key point

 if the given point falls outside the interpolation key range (lower than
 the lowest key point or higher than the highest key point), the nearest
 point value is used; in other words, no extrapolation is performed

 otherwise, the interpolated value is calculated in accordance with the
 first of:

   * the given block
   * the stored blending function, :blend_with
   * a call to :interpolate on a key value object