Find the area of a polygon Given consecutive side lengths s1, s2, s3... s_n of an n-gon inscribed in a circle, find its area. You may assume that the polygon exists. In addition, the polygon will be convex and not self-intersecting, which is enough to guarantee uniqueness. Built-ins that specifically solve this challenge, as well as built-in functions that calculate the circumradius or circumcenter, are banned (this is different from a previous version of this challenge).

Input: The side lengths of the cyclic polygon; may be taken as parameters to a function, stdin, etc.

Output: The area of the polygon.

The answer should be accurate to 6 decimal places and must run within 20 seconds on a reasonable laptop.

This is code golf so shortest code wins!

Specific test cases:

[3, 4, 5] --&gt; 6
[3, 4, 6] --&gt; 5.332682251925386
[3, 4, 6, 7] --&gt; 22.44994432064365
[5, 5, 5, 5] --&gt; 25
[6, 6, 6, 6, 6] --&gt; 61.93718642120281
[6.974973020933265, 2.2393294197257387, 5.158285083300981, 1.4845682771595603, 3.5957940796134173] --&gt; 21.958390804292847
[7.353566082457831, 12.271766915518073, 8.453884922273897, 9.879017670784675, 9.493366404245332, 1.2050010402321778] --&gt; 162.27641678140589


Test case generator:



function randPolygon(n) {
  var left = 2 * Math.PI;
  var angles = [];
  for (var i = 0; i &lt; n - 1; ++i) {
    var r = Math.random() * left;
    angles.push(r);
    left -= r;
  }
  angles.push(left);
  var area = 0;
  var radius = 1 + Math.random() * 9;
  for (var i = 0; i &lt; angles.length; ++i) area += radius * radius * Math.sin(angles[i]) / 2;
  var sideLens = angles.map(function(a) {
    return Math.sin(a / 2) * radius * 2;
  });

  document.querySelector("#radius").innerHTML = radius;
  document.querySelector("#angles").innerHTML = "[" + angles.join(", ") + "]";
  document.querySelector("#inp").innerHTML = "[" + sideLens.join(", ") + "]";
  document.querySelector("#out").innerHTML = area;

  draw(angles);
}

function draw(angles) {
  var canv = document.querySelector("#diagram"),
    ctx = canv.getContext("2d");
  var size = canv.width
  ctx.clearRect(0, 0, size, size);
  ctx.beginPath();
  ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI, true);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(size, size / 2);
  var runningTotal = 0;
  for (var i = 0; i &lt; angles.length; ++i) {
    runningTotal += angles[i];
    var x = Math.cos(runningTotal) * size / 2 + size / 2;
    var y = Math.sin(runningTotal) * size / 2 + size / 2;
    ctx.lineTo(x, y);
  }
  ctx.stroke();
}
document.querySelector("#gen").onclick = function() {
  randPolygon(parseInt(document.querySelector("#sideLens").value, 10));
}
&lt;div id="hints"&gt;
  &lt;p&gt;&lt;strong&gt;These are to help you; they are not part of the input or output.&lt;/strong&gt;
  &lt;/p&gt;
  Circumradius:
  &lt;pre id="radius"&gt;&lt;/pre&gt;
  Angles, in radians, of each sector (this are NOT the angles of the polygon):
  &lt;pre id="angles"&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;div id="output"&gt;
  Input:
  &lt;pre id="inp"&gt;&lt;/pre&gt;
  Output:
  &lt;pre id="out"&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;div id="draw"&gt;
  Diagram:
  &lt;br /&gt;
  &lt;canvas id="diagram" width="200" height="200" style="border:1px solid black"&gt;&lt;/canvas&gt;
&lt;/div&gt;

Number of side lengths:
&lt;input type="number" id="sideLens" step="1" min="3" value="3" /&gt;
&lt;br /&gt;
&lt;button id="gen"&gt;Generate test case&lt;/button&gt;
Python 2, 191 bytes

from math import*
C=sorted(input());l,h=C[-1]/2,sum(C)
while h-l&gt;1e-9:m=l+h;a=[asin(c/m)for c in C[:-1]];f=pi-sum(a);l,h=[l,m/2,h][m*sin(f)&lt;C[-1]:][:2]
print sum(l*l*sin(2*t)for t in a+[f])/2


Uses a binary search to find the radius, then calculates the area of each segment by the angle/radius.

It finds the radius by first summing all but the largest chord angle, and checking the remaining angle to the remaining chord. Those angles are then also used to compute the area of each segment. A segment's area can be negative, if it's angle is bigger than 180 degrees.

Readable implementation:

import math

def segment_angles(line_segments, r):
    return [2*math.asin(c/(2*r)) for c in line_segments]

def cyclic_ngon_area(line_segments):
    line_segments = list(sorted(line_segments))
    lo, hi = max(line_segments) / 2, sum(line_segments)
    while hi - lo &gt; 1e-9:
        mid = (lo + hi) / 2
        angles = segment_angles(line_segments[:-1], mid)
        angles.append(2*math.pi - sum(angles))
        if 2 * mid * math.sin(angles[-1]/2) &lt; line_segments[-1]:
            lo = mid
        else:
            hi = mid
    return sum([lo*lo * math.sin(a) / 2 for a in angles])