#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include<vector>
#include<cstring>
#include<set>
#include <cstdio>
#include<queue>
#include<map>
#define WHITE 0
#define GRAY  1
#define BLACK 2
#define endl '\n'
#define forup(i,a,n) for( int i =a; i < n; i++)
#define llforup(i,a,n) for( ll i =a; i < n; i++)
#define fordown(i,a,n) for( int i =a; i >= n; i--)
#define fornot(i,a,n) for( int i=a;!n;i++)
#define mod  (ll)(1e9+7)
#define putnum(a) printf("%d\n",a)
using namespace std;
typedef long long ll;
inline int readnum()
{
	int p, data = 0; char ch = 0;
	while ((ch != '-') &&( ch < '0' || ch>'9') )//注意运算优先级，逻辑与大于逻辑非
		ch = getchar();//相当于正则表达式的搜索，跳过不需要的字符
	if (ch == '-')
		p = -1, ch = getchar();//不能与if平行放置，不懂为什么，可能是bug
	else p = 1;
	while (ch >= '0' && ch <= '9') data = data * 10 + ch - '0', ch = getchar();//搜索需要的字符
	return data * p;
}
inline int ReadPossitive()
{
	char ch; int data = 0;
	ch = getchar();
	while (ch == ' ' || ch == '\n')ch = getchar();
	while (ch != ' ' && ch != '\n' && ch != EOF)
	{
		data = data * 10 + ch - '0';
		ch = getchar();
	}
	return data;
}
//并查集模板
class DisjointSet {
private:
	vector<int>rank, parent;
public:
	DisjointSet(){}
	DisjointSet(int size)
	{
		rank.resize(size, 0);//默认初始化为0，养成习惯写完整
		parent.resize(size, 0);
		forup(i, 0, size)MakeSet(i);
	}
	void MakeSet(int x)
	{
		parent[x] = x;
		rank[x] = 0;
	}
	bool same(int x, int y)
	{
		return Findroot(x) == Findroot(y);
	}
	void unite(int x, int y)
	{
		link(Findroot(x), Findroot(y));
	}
	inline int Findroot(int x)
	{
		while (x != parent[x])
		{
			x = parent[x];
		}
		return x;
	}
	void link(int rootx, int rooty)
	{
		if (rank[rootx] < rank[rooty])parent[rootx] = parent[rooty];
		else
		{
			parent[rooty] = parent[rootx];
			if (rank[rootx] == rank[rooty])
				rank[rootx]++;
		}
	}
};

//计算几何模板
#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b))<EPS)//保留整数0
class Point {
public:
	double x, y;
public:
	Point() {};
	Point(double x,double y):x(x),y(y){}
	Point operator +(Point p) { return Point(x + p.x, y + p.y);}//p不能为引用的问题怎么解决？
	Point operator -(Point p) { return Point(x - p.x, y - p.y);}
	Point operator *(double a) { return Point(a * x, a * y); }
	Point operator /(double a) { return Point(x / a, y / a); }
	inline double abs() { return sqrt(norm()); }
	inline double norm() { return x * x + y * y; }
	bool operator <(const Point& p)const {
		return x != p.x ? x < p.x : y < p.y;
	}
	bool operator ==(const Point& p)const {
		return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
	}
};
typedef Point Vector;
class Line {
public:
	Point p1, p2;
public:
	Line() {};
	Line(int p1x, int p1y, int p2x, int p2y)
	{
		p1.x = p1x; p1.y = p1y;
		p2.x = p2x; p2.y = p2y;
	}
};
class VectorOperation {//操作符不必继承
public:
	double dot(Point a, Point b)//点乘
	{
		return a.x * b.x + a.y * b.y;
	}
	double cross(Point a, Point b)//叉乘
	{
		return a.x * b.y - a.y * b.x;
	}
	double abs(Point s)
	{
		return sqrt(s.norm());
	}
	double getDistance(Point a, Point b)
	{
		return abs(a - b);
	}
	int rotation(Point p0, Point p1, Point p2)
	{
#define COUNTER_CLOCKWISE -1
#define CLOCKWISE 1
#define ONLINE_BACK -2
#define ONLINE_FRONT 2
#define ON_SEGMENT 0
		Vector a = p1 - p0;Vector b = p2 - p0;
		double Cross = cross(a, b);
		if (Cross > 0.0)return COUNTER_CLOCKWISE;
		if (Cross < 0.0)return CLOCKWISE;
		if (dot(a, b) < 0.0)return ONLINE_BACK;
		if (a.norm() < b.norm())return ONLINE_FRONT;

		return ON_SEGMENT;
#undef COUNTER_CLOCKWISE -1
#undef CLOCKWISE 1
#undef ONLINE_BACK -2
#undef ONLINE_FRONT 2
#undef ON_SEGMENT 0
	}
};

class LineOperation :public VectorOperation{
public:	
	LineOperation() {};
	bool isOrthogonal(Line s1, Line s2)
	{
		return equals(dot(s1.p2-s1.p1, s2.p2 - s2.p1), 0.0);//操作符重载的返回值的内存分配机制尚不可知，似乎返回值没有分配内存，dot的参数不能用引用，否则报错。
	}
	bool isParallel(Line s1, Line s2)
	{
		return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);//外积判断平行，内积判断垂直。
	}
	bool intersectSS(Line s1, Line s2)
	{
		return (rotation(s1.p1, s1.p2, s2.p1) * rotation(s1.p1, s1.p2, s2.p2) <= 0 &&
			    rotation(s2.p1, s2.p2, s1.p1) * rotation(s2.p1, s2.p2, s1.p2) <= 0);//即对两条线段都有另一条线段的两个端点必须在当前线段的两侧
	}//可以证明如果一条线段的计算结果是负二，另一个线段的计算结果必定大于0
	Point projection(Line s, Point p)
	{
		Vector base = s.p1 - s.p2;
		double r = dot(p - s.p1, base) /base.norm();
		return s.p1 + base * r;
	}
	Point reflection(Line s, Point p)
	{
		return p + (projection(s, p)-p) * 2.0;
	}
	double getDistanceLP(Line s, Point p)//点与直线
	{
		return fabs(cross(s.p2 - s.p1, p - s.p1)) / abs(s.p2 - s.p1);
	}
	double getDistanceSP(Line s, Point p)//点与线段
	{
		if (dot(s.p2 - s.p1, p - s.p1) < 0.0)return abs(p - s.p1);//与点p1成钝角
		else if (dot(s.p2 - s.p1, p - s.p2) > 0.0)return abs(p - s.p2);
		else return getDistanceLP(s, p);
	}
	double getDistanceSS(Line s1, Line s2)//线段与线段
	{
		//考虑
		// --
		//----
		if (intersectSS(s1, s2))return 0.0;//如果枚举优化需要16次逻辑，采用分治法的效率和直接使用min函数一样
		else
			return min(min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)), min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)));
		
	}
};
//E-mail 374656045@qq.com

class solve {
private:
	int n;
public://采用邻接表建图,带权无向图
	solve()
	{
		int x1, y1, x2, y2, x3, y3, x4, y4;
		n = readnum();
		LineOperation op;
		forup(i, 0, n)
		{
			x1 = readnum(); y1 = readnum();
			x2 = readnum(); y2 = readnum();
			x3 = readnum(); y3 = readnum();
			x4 = readnum(); y4 = readnum();
			Line s1(x1, y1, x2, y2);
			Line s2(x3, y3, x4, y4);
			printf("%.10f\n", op.getDistanceSS(s1, s2));
		}
	}
	
};
int main(void)
{
	ios_base::sync_with_stdio(0); cin.tie(0);//慎用，cin和scanf混用会导致非MSC++WA
#ifdef DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	solve solution;
#ifdef DEBUG
	fclose(stdin);//关闭文件 
	fclose(stdout);//关闭文件 
#endif
	return 0;

}




Measured memory_bytes: 3248