C#の案件
C#の案件が増えつつある。誘導しているんだけど。
C#開発者をどのように増やすかを考える必要がある。
純粋関数型雑記帳 id:tanakh:20040925 から。
同じ大きさのいくつかの円の面積を求める。63個までしか計算できないし、指数オーダになっている。
public class Calc { static void Test() { ArrayList a = new ArrayList(); Random r = new Random(1); for (int i=0;i<10;++i) a.Add(new double[]{r.NextDouble()*5,r.NextDouble()*5}); Console.WriteLine("{0:F3}",GetCircleArea(a,1)); Console.WriteLine("{0:F3}",GetCircleArea2(a,1)); } public static double GetCircleArea(ArrayList center, double rad) { ArrayList cnt = (ArrayList)center.Clone(); for (int i=0;i<cnt.Count-1;++i) { double[] d1 = (double[])cnt[i]; int j = i+1; while (j < cnt.Count) { double[] d2 = (double[])cnt[j]; if (d1[0] == d2[0] && d1[1] == d2[1]) cnt.RemoveAt(j); else ++j; } } if (cnt.Count > 63) throw new ApplicationException("サイズが大きすぎます"); ulong ui, umx = 1UL << cnt.Count; double[,][][] pos = new double[cnt.Count,cnt.Count][][]; for (int i=0;i<cnt.Count-1;++i) { double[] d1 = (double[])cnt[i]; for (int j=i+1;j<cnt.Count;++j) { double[] d2 = (double[])cnt[j]; double x = d2[0]-d1[0], y = d2[1] - d1[1]; double a = rad*rad/(x*x+y*y)-0.25; if (a <= 0) continue; a = Math.Sqrt(a); double xx = (d1[0]+d2[0])/2, yy = (d1[1]+d2[1])/2; pos[i,j] = pos[j,i] = new double[][]{ new double[]{xx+a*y, yy-a*x, i, j}, new double[]{xx-a*y, yy+a*x, i , j}}; } } ArrayList lst = new ArrayList(); double res = 0; for (ui=1UL;ui<umx;++ui) { int n = 0; lst.Clear(); for (int i=0;i<cnt.Count;++i) { if ((ui & (1UL<<i)) == 0) continue; ++n; for (int j=i+1;j<cnt.Count;++j) { if ((ui & (1UL<<j)) == 0) continue; if (pos[i,j] == null) goto last; for (int k=0;k<2;++k) { int l; for (l=0;l<cnt.Count;++l) { if (l == i || l == j) continue; if ((ui & (1UL<<l)) == 0) continue; if (pos[i,l] == null || pos[j,l] == null) goto not_found; double[] d3 = (double[])cnt[l]; double x = d3[0] - pos[i,j][k][0], y = d3[1] - pos[i,j][k][1]; if (x*x+y*y > rad*rad) goto not_found; } lst.Add(pos[i,j][k]); not_found:; } } } if (lst.Count == 0) { if (n == 1) res += Math.PI*rad*rad; continue; } double v1 = ((double[])lst[0])[2]; double v2 = ((double[])lst[0])[3]; for (int i=1;i<lst.Count;++i) { int j; for (j=i;j<lst.Count;++j) { double vv1 = ((double[])lst[j])[2]; double vv2 = ((double[])lst[j])[3]; if (v1 == vv1) {v1 = vv2; break;} if (v1 == vv2) {v1 = vv1; break;} } if (j == lst.Count) throw new ApplicationException("Not found"); object tmp = lst[i]; lst[i] = lst[j]; lst[j] = tmp; } if (v1 != v2) throw new ApplicationException("Not match"); double s,a,b,c, d = 0; if (lst.Count > 2) { c = GetLength((double[])lst[0], (double[])lst[1]); for (int i=2;i<lst.Count;++i) { a = c; b = GetLength((double[])lst[i], (double[])lst[i-1]); c = GetLength((double[])lst[i], (double[])lst[0]); s = (a+b+c)/2; d += Math.Sqrt(s*(s-a)*(s-b)*(s-c)); } } for (int i=0;i<lst.Count;++i) { double x = GetLength((double[])lst[i], (double[])lst[(i+1)%lst.Count]); d += Math.Asin(x/rad/2)*rad*rad - x/2*Math.Sqrt(rad*rad-x*x/4); } res += n%2 == 1 ? d : -d; last:; } return res; } public static double GetLength(double[] d1, double[] d2) { double x = d1[0]-d2[0]; double y = d1[1]-d2[1]; return Math.Sqrt(x*x+y*y); } public static double GetCircleArea2(ArrayList center, double rad) { double res = 0, d = 1e-2, l, t, r, b; l = b = double.MaxValue; t = r = double.MinValue; foreach (double[] dd in center) { if (dd[0] < l) l = dd[0]; if (dd[0] > r) r = dd[0]; if (dd[1] < b) b = dd[1]; if (dd[1] > t) t = dd[1]; } l -= rad; b -= rad; t += rad; r += rad; for (double x=l;x<=r;x+=d) { for (double y=b;y<=t;y+=d) { foreach (double[] dd in center) { double xx = x-dd[0]; double yy = y-dd[1]; if (xx*xx+yy*yy < rad*rad) { res += d*d; break; } } } } return res; } }