#include <bits/stdc++.h>
using namespace std;
template <class T>
void dbs(string str, T t) {
  cerr << str << " : " << t << "\n";
}
template <class T, class... S>
void dbs(string str, T t, S... s) {
  int idx = str.find(',');
  cerr << str.substr(0, idx) << " : " << t << ",";
  dbs(str.substr(idx + 1), s...);
}
template <class S, class T>
ostream& operator<<(ostream& os, const pair<S, T>& p) {
  return os << "(" << p.first << ", " << p.second << ")";
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& p) {
  os << "[ ";
  for (auto& it : p) os << it << " ";
  return os << "]";
}
template <class T>
ostream& operator<<(ostream& os, const set<T>& p) {
  os << "[ ";
  for (auto& it : p) os << it << " ";
  return os << "]";
}
template <class S, class T>
ostream& operator<<(ostream& os, const map<S, T>& p) {
  os << "[ ";
  for (auto& it : p) os << it << " ";
  return os << "]";
}
template <class T>
void prc(T a, T b) {
  cerr << "[";
  for (T i = a; i != b; ++i) {
    if (i != a) cerr << ", ";
    cerr << *i;
  }
  cerr << "]\n";
}
const int n = 100010;
class SegTree {
 public:
  vector<pair<int, int> > values;
  SegTree(int n, const vector<pair<int, int> >& points) {
    values.resize(4 * int(points.size()) + 1);
    build(1, 1, n, points);
  }
  void build(int node, int b, int e, const vector<pair<int, int> >& points) {
    if (b > e) return;
    if (b == e) {
      values[node] = make_pair(points[b].second, points[b].second);
      return;
    }
    build(2 * node, b, (b + e) / 2, points);
    build(2 * node + 1, (b + e) / 2 + 1, e, points);
    values[node] =
        make_pair(min(values[2 * node].first, values[2 * node + 1].first),
                  max(values[2 * node].second, values[2 * node + 1].second));
    return;
  }
  pair<int, int> query(int node, int b, int e, int i, int j) {
    if (b > e || i > e || j < b) return make_pair(INT_MAX, INT_MIN);
    if (i <= b and e <= j) {
      return values[node];
    }
    pair<int, int> left = query(2 * node, b, (b + e) / 2, i, j);
    pair<int, int> right = query(2 * node + 1, (b + e) / 2 + 1, e, i, j);
    return make_pair(min(left.first, right.first),
                     max(left.second, right.second));
  }
};
int getPosition(double width, int index1, int n,
                const vector<pair<int, int> >& points) {
  int low = index1, high = n;
  while (low < high) {
    if (low + 1 == high) {
      if (points[high].first - points[index1].first <= width) {
        return high;
      } else {
        return low;
      }
    }
    int mid = (low + high) / 2;
    if (points[mid].first - points[index1].first <= width) {
      low = mid;
    } else {
      high = mid - 1;
    }
  }
  return low;
}
bool possible(double dist, int n, const vector<pair<int, int> >& points,
              SegTree& sgt) {
  dist *= 2.0;
  for (int i = (int)(1); i <= (int)(n); i++) {
    int j = getPosition(dist, i, n, points);
    pair<int, int> rightSide = sgt.query(1, 1, n, j + 1, n);
    pair<int, int> leftSide = sgt.query(1, 1, n, 1, i - 1);
    double minCord = min(rightSide.first, leftSide.first);
    double maxCord = max(rightSide.second, leftSide.second);
    if (maxCord - minCord <= dist) return true;
  }
  return false;
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin >> n;
  vector<pair<int, int> > points;
  points.push_back(make_pair(-1, -1));
  for (int i = (int)(0); i <= (int)(n - 1); i++) {
    int a1, b1;
    cin >> a1 >> b1;
    tie(a1, b1) = make_tuple(a1 - b1, a1 + b1);
    points.push_back(make_pair(a1, b1));
  }
  sort(points.begin() + 1, points.end());
  SegTree sgt(n, points);
  double low = 0;
  double high = 2000000010.0;
  for (int times = (int)(0); times <= (int)(100); times++) {
    double mid = (low + high) / 2.0;
    if (possible(mid, n, points, sgt)) {
      high = mid;
    } else {
      low = mid;
    }
  }
  cout << fixed << setprecision(10) << high << "\n";
  return 0;
}
