#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const double EPS=1e-8;
const double INF=1e77;
const double PI=acos(-1);

template<class T>
struct point{
	T x,y;
	point operator+(const point &a)const{ return (point){x+a.x,y+a.y}; }
	point operator-(const point &a)const{ return (point){x-a.x,y-a.y}; }
};

template<class T>
point<T> operator*(T c,const point<T> &a){ return (point<T>){c*a.x,c*a.y}; }

bool operator<(const point<double> &a,const point<double> &b){
	return a.x+EPS<b.x || abs(a.x-b.x)<EPS && a.y+EPS<b.y;
}

bool operator==(const point<double> &a,const point<double> &b){
	return abs(a.x-b.x)<EPS && abs(a.y-b.y)<EPS;
}

template<class T>
struct line{
	point<T> a,b;
};

template<class T>
struct segment{
	point<T> a,b;
	operator line<T>()const{ return (line<double>){a,b}; }
};

template<class T>
struct polygon:vector< point<T> >{
	polygon(){}
	polygon(int n):vector< point<T> >(n){}
};

template<class T>
T dot(const point<T> &a,const point<T> &b){ return a.x*b.x+a.y*b.y; }

template<class T>
T cross(const point<T> &a,const point<T> &b){ return a.x*b.y-a.y*b.x; }

template<class T>
double arg(const point<T> &a){
	double t=atan2(a.y,a.x);
	return t<0?t+2*PI:t;
}

enum{CCW=1,CW=-1,ON=0};
int ccw(const point<double> &a,const point<double> &b,const point<double> &c){
	double rdir=cross(b-a,c-a);
	if(rdir> EPS) return CCW;
	if(rdir<-EPS) return CW;
	return ON;
}

point<double> get_intersect(const line<double> &L1,const line<double> &L2){
	double a1=cross(L1.b-L1.a,L2.b-L2.a);
	double a2=cross(L1.b-L1.a,L1.b-L2.a);
	if(abs(a1)<EPS) return L1.a;
	return L2.a+a2/a1*(L2.b-L2.a);
}

template<class T>
T dist(const point<T> &a,const point<T> &b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool cover(const segment<double> &S,const point<double> &p){
	return dist(S.a,p)+dist(p,S.b)<dist(S.a,S.b)+EPS;
}

bool intersect(const segment<double> &S1,const segment<double> &S2){
	if(max(S1.a.x,S1.b.x)+EPS<min(S2.a.x,S2.b.x)
	|| max(S1.a.y,S1.b.y)+EPS<min(S2.a.y,S2.b.y)
	|| max(S2.a.x,S2.b.x)+EPS<min(S1.a.x,S1.b.x)
	|| max(S2.a.y,S2.b.y)+EPS<min(S1.a.y,S1.b.y)) return false;
	return ccw(S1.a,S1.b,S2.a)*ccw(S1.a,S1.b,S2.b)<=0
		&& ccw(S2.a,S2.b,S1.a)*ccw(S2.a,S2.b,S1.b)<=0;
}

template<class T>
T area2(const polygon<T> &G){
	int n=G.size();
	T a=0;
	rep(i,n) a+=cross(G[i],G[(i+1)%n]);
	return abs(a);
}

int main(){
	int n; scanf("%d",&n);
	polygon<double> F(n);
	rep(i,n) scanf("%lf%lf",&F[i].x,&F[i].y);

	// arrangement!!!!!!!
	vector< point<double> > P=F;
	rep(i,n-1) for(int j=i+1;j<n-1;j++) {
		segment<double> S1={F[i],F[i+1]};
		segment<double> S2={F[j],F[j+1]};
		if(intersect(S1,S2)){
			P.push_back(get_intersect(S1,S2));
		}
	}
	sort(P.begin(),P.end());
	P.erase(unique(P.begin(),P.end()),P.end());

	int N=P.size();
	vector<int> G[20000];
	rep(i,n-1){
		segment<double> S={F[i],F[i+1]};
		vector< point<double> > Q;
		rep(j,N) if(cover(S,P[j])) Q.push_back(P[j]);
		sort(Q.begin(),Q.end());
		rep(j,(int)Q.size()-1){
			int u=find(P.begin(),P.end(),Q[ j ])-P.begin();
			int v=find(P.begin(),P.end(),Q[j+1])-P.begin();
			G[u].push_back(v);
			G[v].push_back(u);
		}
	}

	// trace
	// 最初の二点を決める
	int u_start0=0;
	rep(u,N) if(P[u].y<P[u_start0].y) u_start0=u;
	int u_start1=-1;
	rep(i,G[u_start0].size()){
		int v=G[u_start0][i];
		if(u_start1==-1 || arg(P[v]-P[u_start0])<arg(P[u_start1]-P[u_start0])) u_start1=v;
	}

	vector<int> path;
	path.push_back(u_start0);
	int u=u_start1,u_prev=u_start0;
	do{
		path.push_back(u);

		double theta=arg(P[u_prev]-P[u]);
		int u_next=-1;
		double theta_next=INF;
		rep(i,G[u].size()){
			int v=G[u][i];
			double theta_tmp=arg(P[v]-P[u]);
			while(theta_tmp<theta+EPS) theta_tmp+=2*PI;
			if(theta_tmp<theta_next){
				theta_next=theta_tmp;
				u_next=v;
			}
		}

		u_prev=u;
		u=u_next;
	}while(u!=u_start1 || u_prev!=u_start0);

	polygon<double> ans;
	rep(i,path.size()) ans.push_back(P[path[i]]);
	printf("%.15f\n",area2(ans)/2);

	return 0;
}

Measured memory_bytes: 1796