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 - Perl

単純なニュートン法。1000までならこれで十分。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
my $d = 10 ** -12;

sub check($$$){
  my ($x, $y, $d) = @_;
  return abs($y - $x ** 3) < $d;
}

sub improve($$){
  my ($x, $a) = @_;
  return (2 * $x ** 3 + $a) / (3 * $x ** 2);
}

sub cube_root($){
  my $a = $_[0];
  return 0 if $a == 0;
  my $p = 1;
  my $q;
  until(check($p, $a, $d)){
    $q = $p;
    $p = improve($p, $a);
  }
  $p;
}

もっと精度が必要な場合は、Math::BigFloatを使うとよいと思います。(check, improveはまったく同じです。)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use Math::BigFloat;

my $d = Math::BigFloat->new("1E-12");

sub check($$$){
  my ($x, $y, $d) = @_;
  return abs($y - $x ** 3) < $d;
}

sub improve($$){
  my ($x, $a) = @_;
  return (2 * $x ** 3 + $a) / (3 * $x ** 2);
}

sub cube_root($){
  my $a = Math::BigFloat->new($_[0]);
  my $p = Math::BigFloat->bone();
  my $q;
  until(check($p, $a, $d)){
    $q = $p;
    $p = improve($p, $a);
  }
  $p->ffround(-12);
}

Index

Feed

Other

Link

Pathtraq

loading...