import java.util.*;
import java.lang.*;
import java.io.*;
import java.text.*;
import java.util.function.*;
import static java.lang.Math.*;

class Util {
	static IllegalArgumentException badArgf(String fmt, Object... args) {
		return new IllegalArgumentException(String.format(fmt, args));
	}

	static final DecimalFormat humanFloatFormat = new DecimalFormat("#.###");

	static String humanFloat(double x) {
		return humanFloatFormat.format(x);
	}

	static String trace(Exception e) {
		StringWriter sw = new StringWriter();
		e.printStackTrace(new PrintWriter(sw));
		return sw.toString();
	}
}

class Vec2 {
	public final double x, y;
	public Vec2(double x, double y) { this.x = x; this.y = y; }
	public static Vec2 Vec2(double x, double y) { return new Vec2(x, y); }
	public Vec2 add(Vec2 b) { return Vec2(x + b.x, y + b.y); }
	public Vec2 sub(Vec2 b) { return Vec2(x - b.x, y - b.y); }
	public Vec2 mul(Vec2 b) { return Vec2(x * b.x, y * b.y); }
	public Vec2 mul(double b) { return Vec2(x * b, y * b); }
	public Vec2 div(Vec2 b) { return Vec2(x / b.x, y / b.y); }
	public Vec2 div(double b) { return Vec2(x / b, y / b); }
	@Override public String toString() { return String.format("(%s, %s)", Util.humanFloat(x), Util.humanFloat(y)); }
	public Vec2 min(Vec2 b) { return Vec2(Math.min(x, b.x), Math.min(y, b.y)); }
	public Vec2 max(Vec2 b) { return Vec2(Math.max(x, b.x), Math.max(y, b.y)); }
}

class AABB {
	public final Vec2 a, b;
	public AABB(Vec2 a, Vec2 b) { this.a = a; this.b = b; }
	public static AABB AABB(Vec2 a, Vec2 b) { return new AABB(a, b); }
	@Override public String toString() { return String.format("A = %s, B = %s", a, b); }

	public static AABB bound(int count, IntFunction<AABB> ithBB) {
		if (count <= 0) throw Util.badArgf("AABB.bound: count = %d.", count);
		var bb = ithBB.apply(0);
		Vec2 a = bb.a, b = bb.b;
		for (int i = 1; i < count; i++) {
			bb = ithBB.apply(i);
			a = a.min(bb.a);
			b = b.max(bb.b);
		}
		return AABB(a, b);
	}

	public static AABB bound(List<AABB> bbs) {
		if (bbs.size() == 0) throw Util.badArgf("AABB.bound: count = %d.", bbs.size());
		var bb = bbs.get(0);
		Vec2 a = bb.a, b = bb.b;
		for (int i = 1; i < bbs.size(); i++) {
			bb = bbs.get(i);
			a = a.min(bb.a);
			b = b.max(bb.b);
		}
		return AABB(a, b);
	}

	public static AABB bound(Iterator<AABB> bbs) {
		if (!bbs.hasNext()) throw Util.badArgf("AABB.bound: no items.");
		var bb = bbs.next();
		Vec2 a = bb.a, b = bb.b;
		while (bbs.hasNext()) {
			bb = bbs.next();
			a = a.min(bb.a);
			b = b.max(bb.b);
		}
		return AABB(a, b);
	}
}

class MyPreciousObject {
	AABB bb;
	Vec2 pos;
	String name;
	Object someOtherData;

	public MyPreciousObject(AABB bb) {
		this.bb = bb;
	}
}

class Ideone
{
	static double benchmark(String title, Supplier payload) {
		return benchmark(title, payload, -1);
	}

	static double benchmark(String title, Supplier payload, double reference) {
		long start = System.nanoTime();
		var payloadResult = payload.get();
		double time = (System.nanoTime() - start) * 1e-9;
		// использовать payloadResult желательно даже без соответствующего %s, а то мало ли СОПТИМИЗИРУЕТСЯ при неиспользовании.
		System.out.println(String.format(
			"%s: %.2f s%s%s",
			title, time, reference >= 0 ? String.format(" (%s)", judgement(time, reference)) : "",
			payloadResult != null ? String.format("\n%s\n", payloadResult) : ""));
		return time;
	}

	static String judgement(double time, double refTime) {
		final double absThreshold = 0.1, relThreshold = .1;

		return time <= absThreshold || refTime <= absThreshold ?
			String.format("can't judge, min. required time is %.1f s", absThreshold) :
			Math.max(time, refTime) > (1 + relThreshold) * Math.min(time, refTime) ?
			String.format("%.0f%% %s",
				Math.abs((time < refTime ? refTime / time : time / refTime) - 1) * 100,
				time < refTime ? "faster" : "slower") :
			String.format("no observable difference, min. %.0f%% required", relThreshold * 100);
	}

	static void benchmark() {
		var objs = new ArrayList<MyPreciousObject>();
		var rand = new Random(1);
		for (int i = 0; i < 1_000_000; i++) {
			Vec2 a = Vec2.Vec2(rand.nextDouble(), rand.nextDouble()).mul(100);
			objs.add(new MyPreciousObject(
				AABB.AABB(a, a.add(Vec2.Vec2(rand.nextDouble(), rand.nextDouble()).mul(10)))
			));
		}
		var bbList = new ArrayList<AABB>();

		final int TRIALS = 3, AMPLIFY = 50;
		for (int iTrial = 0; iTrial < TRIALS; iTrial++) {
			System.out.printf("%s--- TRIAL %d/%d ---\n", iTrial > 0 ? "\n" : "", 1 + iTrial, TRIALS);
			var ref = benchmark("bound(List<AABB>)", () -> {
				AABB result = null;
				for (int iAmp = 0; iAmp < AMPLIFY; iAmp++) {
					bbList.clear();
					bbList.ensureCapacity(objs.size());
					for (int i = 0; i < objs.size(); i++)
						bbList.add(objs.get(i).bb);
					result = AABB.bound(bbList);
				}
				return result;
			});

			benchmark("bound(int -> AABB)", () -> {
				AABB result = null;
				for (int iAmp = 0; iAmp < AMPLIFY; iAmp++)
					result = AABB.bound(objs.size(), i -> objs.get(i).bb);
				return result;
			}, ref);

			benchmark("bound(List<MyPreciousObject>.map(obj -> AABB).iterator)", () -> {
				AABB result = null;
				for (int iAmp = 0; iAmp < AMPLIFY; iAmp++)
					result = AABB.bound(objs.stream().map(obj -> obj.bb).iterator());
				return result;
			}, ref);
		}
	}

	public static void main (String[] args) throws java.lang.Exception
	{
		try {
			benchmark();
		} catch (Exception e) {
			System.out.println(Util.trace(e));
		}
	}
}