challenge 立方根の計算

xは0以上1000未満の実数です。 y * y * y = xになるような実数y(立方根)を小数点以下12桁以上の正確さで 求める関数cube_rootを作って下さい。

ただし、このお題の趣旨は実数区間での探索なので、 立方根関数があっても使ってはいけません。 指数関数と対数関数も禁止します。

Pythonで表現した入出力の例:

>>> cube_root(10.0)
2.1544346900318834
>>> _ ** 3
9.9999999999999947
>>> cube_root(100.0)
4.6415888336127793
>>> _ ** 3
100.00000000000003

Posted feedbacks - C#

ニュートン法にしました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public static double CubeRoot(double x)
{
  double a0 = (double)(-x);
  double[] a = { a0, 0.0, 0.0, 1.0 };
  return SolveAlgebraicEquationByNewtonMethod(a, 1e-12);
}

delegate double MathFunc(double x);

static double SolveAlgebraicEquationByNewtonMethod(double[] a, double delta)
{
  MathFunc f = CreateFunc(a);
  MathFunc fPrime = CreateFunc(Derivative(a));
  double x = 1.0;
  while (NearlyEquals(fPrime(x), 0.0, double.Epsilon))
    x += 1.0;
  double betterX = 0;
  while (true)
  {
    betterX = Newton(f, fPrime, x);
    if (NearlyEquals(x, betterX, delta))
      break;
    x = betterX;
  }
  return betterX;
}

static MathFunc CreateFunc(double[] a)
{
  return delegate(double x)
  {
    double fx = 0.0;
    for (int i = 0; i < a.Length; i++)
    {
      double d = a[i];
      if (NearlyEquals(d, 0.0, double.Epsilon))
        continue;
      for (int j = 0; j < i; j++)
        d *= x;
      fx += d;
    }
    return fx;
  };
}

static double[] Derivative(double[] a)
{
  double[] aPrime = new double[a.Length - 1];
  for (int i = 1; i < a.Length; i++)
  {
    aPrime[i - 1] = a[i] * (double)i;
  }
  return aPrime;
}

static double Newton(MathFunc f, MathFunc fPrime, double x)
{
  return x - (f(x) / fPrime(x));
}

static bool NearlyEquals(double d1, double d2, double delta)
{
  return (((d1 - d2) <= delta) && ((d2 - d1) <= delta));
}

Index

Feed

Other

Link

Pathtraq

loading...