数値の立方根を計算する


12

このゴルフの目標は、入力として与えられた数値の立方根を計算して出力するプログラムまたは関数を作成することです。
ルール:

  • 外部リソースなし
  • 組み込みのキューブルート関数は使用しません。
  • 数値を累乗する(平方根、4番目の根などを含む)メソッド/演算子を使用しません。
  • 関数/プログラムは、入力として浮動小数点数と負数を受け入れられる必要があります。
  • 立方根が浮動小数点数である場合は、小数点以下4桁に丸めます。
  • これはコードゴルフで、バイト単位の最短コードが勝ちです。

テストケース:

27 --> 3
64 --> 4
1  --> 1
18.609625 --> 2.65
3652264 --> 154
0.001 --> 0.1
7  --> 1.9129

上記のすべてのテストケースを使用して-27 --> -3、負の数(、-64 --> -4...)をテストできます。


いまいましい、あなたが正確な立方体を持つ数字だけを許可した場合、私は素晴らしいゴルフをするだろう
ヨー

1
テストケースから判断すると、プログラムは実数のみを処理する必要があると思いますか?
user12205 14

@aceは複雑を追加し、コード内の2文字を変更します;)
yo

2
小数点以下4桁に丸めることは強力な要件ですか?または、「小数点以下4桁以上を表示する必要はありません」のようなものでしょうか?
ビクターStafusa 14

Exp(ln(x)/ 3)(およびそのいくつかのクローン)を使用した私の答えを参照して、Expが許可されているかどうかを明確にしてください。pow(x、1/3)はそうではないと仮定します(技術的には立方根関数ではありませんが)
Level River St 14

回答:


6

J:16文字

Haskell回答の緩やかな翻訳:

-:@((%*~)+])^:_~

テストケース:

   -:@((%*~)+])^:_~27
3
   -:@((%*~)+])^:_~64
4
   -:@((%*~)+])^:_~1
1
   -:@((%*~)+])^:_~18.609625
2.65
   -:@((%*~)+])^:_~3652264
154
   -:@((%*~)+])^:_~0.001
0.1
   -:@((%*~)+])^:_~7
1.91293

それはこのように動作します:

     (-:@((% *~) + ])^:_)~ 27
↔ 27 (-:@((% *~) + ])^:_) 27
↔ 27 (-:@((% *~) + ])^:_) 27 (-:@((% *~) + ])) 27
↔ 27 (-:@((% *~) + ])^:_) -: ((27 % 27 * 27) + 27)
↔ 27 (-:@((% *~) + ])^:_) 13.5185
↔ 27 (-:@((% *~) + ])^:_) 27 (-:@((% *~) + ])) 13.5185
↔ 27 (-:@((% *~) + ])^:_) -: ((27 % 13.5185 * 13.5185) + 13.5185)
↔ 27 (-:@((% *~) + ])^:_) 6.83313
...

言葉で:

half =. -:
of =. @
divideBy =. %
times =. *
add =. +
right =. ]
iterate =. ^:
infinite =. _
fixpoint =. iterate infinite
by_self =. ~

-:@((%*~)+])^:_~ ↔ half of ((divideBy times by_self) add right) fixpoint by_self

二項分岐と~右端にあるため、最高の冗長な翻訳の1つではありません。


19

ハスケル-35

c n=(iterate(\x->(x+n/x/x)/2)n)!!99

実行例:

c 27  =>  3.0
c 64  =>  4.0
c 1  =>  1.0
c 18.609625  =>  2.6500000000000004  # only first 4 digits are important, right?
c 3652264  =>  154.0
c 0.001  =>  0.1
c 7  =>  1.9129311827723892
c (-27)  =>  -3.0
c (-64)  =>  -4.0

さらに、importした場合Data.Complex、複素数でも機能し、数値の根の1つを返します(3つあります)。

c (18:+26)  =>  3.0 :+ 1.0

:+オペレータは、「プラスとして読まれるべきであるI回」


1
これは+1に値します。私は最後の1時間、一般化されたn番目のルートアルゴリズムをリファクタリングしてきましたが、ちょうど同じ結果になりました。ブラボー
primo

@primo私は即座にすべてのn番目のルート近似アルゴリズムを思い出し、APLのTaylor / Maclaurinシリーズをあきらめた後、これを使用しました。
mniip 14

私が得たニュートン法を使用してx=(2*x+n/x/x)/3、なぜ使用できるのか説明できますx=(x+n/x/x)/2か?それは遅く収束するが、それは収束し、なぜ私が説明することはできません...
マイケル・M.

@Michaelは、を取得した場合x=cbrt(n)x=(x+n/x/x)/2trueになるためです。だから、あなたの表現のために真である
mniip

@Michael私はこの方法でそこに着きました:codepad.org/gwMWniZB
primo

7

SageMath、(69)62バイト

ただし、結果が得られるとは思わないでください。すべての数値をランダムに調べるのは非常に困難です。

def r(x):
 y=0
 while y*y*y-x:y=RR.random_element()
 return "%.4f"%y

あなたが切り捨てを主張しなかった場合:

def r(x):
 y=0
 while y*y*y-x:y=RR.random_element()
 return y

SageMath、12バイト、exp許可されている場合

すべてのものに有効:ポジティブ、ネガティブ、ゼロ、コンプレックス...

exp(ln(x)/3)

数字を累乗できる演算子を使用していると思います。
user12205 14

ああ、正しい、編集

6
まだ要件を満たしている途方もなく愚かなアルゴリズムの場合は+1。
機械式カタツムリ14

@Mechanicalsnailありがとう。私がやっていることは一種の不況であることは明らかだと思います。しかし、exp許されれば、私は12歳になり、まったく愚かではありません:)
yo

これを考慮すると、exp「その値関数は定数をe引数の累乗した定数、特に関数である。」が「指数関数」の略であり、及び方法/オペレータのいかなる使用は」存在しないこと数値を累乗することができます」expは許可されていません。
mbomb007

5

Python-62バイト

x=v=input()
exec"x*=(2.*v+x*x*x)/(v+2*x*x*x or 1);"*99;print x

完全な浮動小数点精度まで評価します。使用される方法は、ハレーの方法です。各反復は最後の3倍の正しい数字を生成するため、99回の反復は少しやり過ぎです。

入出力:

27 -> 3.0
64 -> 4.0
1 -> 1.0
18.609625 -> 2.65
3652264 -> 154.0
0.001 -> 0.1
7 -> 1.91293118277
0 -> 1.57772181044e-30
-2 -> -1.25992104989

これはどのように作動しますか?
ちょうど半分14

1
@justhalfこれは基本的にニュートンの近似法だと思います。
yo

ところで、失敗します0

失敗します-2、それはごめんなさい。
よ」

3
@plg問題の説明は、指数関数の使用を禁止していますv**(1/.3)。そうでなければ、確実な勝者になります。
プリモ14

3

Javascript(55)

function f(n){for(i=x=99;i--;)x=(2*x+n/x/x)/3;return x}

ボーナス、すべての根の一般的な定式化
function f(n,p){for(i=x=99;i--;)x=x-(x-n/Math.pow(x,p-1))/p;return x}

立方根、ちょうど使用するためにf(n,3)、平方根f(n,2)など、...例:f(1024,10)リターン2


ニュートン法に基づいた説明

見つける:f(x) = x^3 - n = 0、解決策はn = x^3
派生です:f'(x) = 3*x^2

繰り返す:
x(i+1) = x(i) - f(x(i))/f'(x(i)) = x(i) + (2/3)*x + (1/3)*n/x^2

テスト

[27,64,1,18.609625,3652264,0.001,7].forEach(function(n){console.log(n + ' (' + -n + ') => ' + f(n) + ' ('+ f(-n) +')')})

27 (-27) => 3 (-3)
64 (-64) => 4 (-4)
1 (-1) => 1 (-1)
18.609625 (-18.609625) => 2.65 (-2.65)
3652264 (-3652264) => 154 (-154)
0.001 (-0.001) => 0.09999999999999999 (-0.09999999999999999)
7 (-7) => 1.912931182772389 (-1.912931182772389) 

1文字短く:function f(n){for(i=x=99;i--;)x-=(x-n/x/x)/3;return x}
コピー

47バイトに減らすことができますf=(n)=>eval('for(i=x=99;i--;)x=(2*x+n/x/x)/3')
ルイスフェリペデジェススムニョス

2

PHP-81バイト

反復ソリューション:

$i=0;while(($y=abs($x=$argv[1]))-$i*$i*$i>1e-4)$i+=1e-5;@print $y/$x*round($i,4);

ゼロの立方根を計算しようとするとどうなりますか?
ビクターStafusa 14

単に「0」を出力します(エラー抑制演算子のおかげで-「@」)。
ラズバン14

1
0.0001置き換えることができる1e-40.00001ことで1e.5
ComFreek 14

これにはPHP <7が必要です(PHP 7で0/0提供さNANれます)。$i=0;不要です(-5バイト。そうでない場合、for1バイト節約されます。)後のスペースprintは不要です(-1バイト)。-Rで3バイト節約できます$argn
タイタス

while(1e-4+$i*$i*$i<$y=abs($x=$argn))(-2バイト)で一対の括弧を保存します。
タイタス

2

Perl、92バイト

sub a{$x=1;while($d=($x-$_[0]/$x/$x)/3,abs$d>1e-9){$x-=$d}$_=sprintf'%.4f',$x;s/\.?0*$//;$_}
  • この関数aは、右端に不要な小数部または無意味なゼロを含まない数値の文字列を返します。

結果:

              27 --> 3
             -27 --> -3
              64 --> 4
             -64 --> -4
               1 --> 1
              -1 --> -1
       18.609625 --> 2.65
      -18.609625 --> -2.65
         3652264 --> 154
        -3652264 --> -154
           0.001 --> 0.1
          -0.001 --> -0.1
               7 --> 1.9129
              -7 --> -1.9129
 0.0000000000002 --> 0.0001
-0.0000000000002 --> -0.0001
               0 --> 0
              -0 --> 0

によって生成されます

sub test{
    my $a = shift;
    printf "%16s --> %s\n", $a, a($a);
    printf "%16s --> %s\n", "-$a", a(-$a);
}
test 27;
test 64;
test 1;
test 18.609625;
test 3652264;
test 0.001;
test 7;
test "0.0000000000002";
test 0;

計算は、ニュートンの方法に基づいています。

Calculation


2

APL-31

(×X)×+/1,(×\99⍴(⍟|X←⎕)÷3)÷×\⍳99

という事実を使用しますが、cbrt(x)=e^(ln(x)/3)単純なべき乗を行う代わりに、e^xTaylor / Maclaurinシリーズを使用して計算します。

サンプルの実行:

⎕: 27
3
⎕: 64
4
⎕: 1
1
⎕: 18.609625
2.65
⎕: 3652264
154
⎕: 0.001
0.1
⎕: 7
1.912931183
⎕: ¯27
¯3
⎕: ¯7
¯1.912931183

そこだと見てJの答えは16文字で、私はAPLで本当にひどいでなければなりません...


2

Java(登録商標)、207 182 181

時々ゴルフをするとき、ビールを2つ持っていて本当にひどく悪い

class n{public static void main(String[]a){double d=Double.valueOf(a[0]);double i=d;for(int j=0;j<99;j++)i=(d/(i*i)+(2.0*i))/3.0;System.out.println((double)Math.round(i*1e4)/1e4);}}

反復ニュートンの近似法は、99回の反復を実行します。

これがunGolfedです:

class n{
    public static void main(String a[]){
        //assuming the input value is the first parameter of the input
        //arguments as a String, get the Double value of it
        double d=Double.valueOf(a[0]);
        //Newton's method needs a guess at a starting point for the 
        //iterative approximation, there are much better ways at 
        //going about this, but this is by far the simplest. Given
        //the nature of the problem, it should suffice fine with 99 iterations
        double i=d;

        //make successive better approximations, do it 99 times
        for(int j=0;j<99;j++){
            i=( (d/(i*i)) + (2.0*i) ) / 3.0;
        }
        //print out the answer to standard out
        //also need to round off the double to meet the requirements
        //of the problem.  Short and sweet method of rounding:
        System.out.println( (double)Math.round(i*10000.0) / 10000.0 );
    }
}

1
args変数の名前をのようなものに変更して、z6文字減らすことができます。forループの本体のスペースと中括弧を削除して、3文字削減できます。に置き換え10000.01e4、6文字削減できます。クラスはパブリックである必要がないため、さらに7文字を削減できます。これにより、185文字に削減されます。
ビクターStafusa 14

最後のキャストは本当に必要ですか?それは私のためではありません。
ビクターStafusa 14

@Victor良い目をありがとう、10000.0倍精度のE表記法の使用は見事なアイデアでした。質問の設計により、これを機能するcliクラスの代わりにメソッドにすることは合法だと思います。Javaでは、チャンスがあるとは思わなかったので、機能的な面で誤りました。
md_rasler 14

CodeGolfへようこそ!これがどのように機能するかについての回答を説明することを忘れないでください!
ジャスティン14

@Quincunx、ありがとう、推奨される変更を行いました。
md_rasler 14

2

TI-Basic、26 24バイト

Input :1:For(I,1,9:2Ans/3+X/(3AnsAns:End

それは^演算子を直接使用します。それはルールで禁止されている
mniip

@mniip:e^TI-83シリーズでは単一のオペレーターですか?覚えていない。いずれにせよ、それはルールの精神に違反しています。
機械式カタツムリ14

@Mechanicalsnail私が言うことは関係ありません。ほとんどの言語で、あなただけの何ができるexp(ln(x)/3)e^(ln(x/3))、あなたは、これら二つのいずれかを許可している場合。しかし、どういうわけか私はルールによって許可されるにはexp(ln(x)/a)あまりにも同等に理解してx^(1/a)います:-/
yo

指数関数:「値が引数の累乗の定数である関数、特に定数がeである関数」...「パワーに数を上げることができる方法/演算子の使用はない」
mbomb007

@ mbomb007をキャッチしてくれてありがとう、私は3年以上前にこの答えを書いたので、すぐにそれを修正するつもりです。
ティムテック

2

Js 57バイト

f=(x)=>eval('for(w=0;w**3<1e12*x;w++);x<0?-f(-x):w/1e4')

f=(x)=>eval('for(w=0;w**3<1e12*x;w++);x<0?-f(-x):w/1e4')
document.getElementById('div').innerHTML += f(-27) + '<br>'
document.getElementById('div').innerHTML += f(-64) + '<br>'
document.getElementById('div').innerHTML += f(-1) + '<br>'
document.getElementById('div').innerHTML += f(-18.609625) + '<br>'
document.getElementById('div').innerHTML += f(-3652264) + '<br>'
document.getElementById('div').innerHTML += f(-0.001) + '<br>'
document.getElementById('div').innerHTML += f(-7) + '<br><hr>'
document.getElementById('div').innerHTML += f(27) + '<br>'
document.getElementById('div').innerHTML += f(64) + '<br>'
document.getElementById('div').innerHTML += f(1) + '<br>'
document.getElementById('div').innerHTML += f(18.609625) + '<br>'
document.getElementById('div').innerHTML += f(3652264) + '<br>'
document.getElementById('div').innerHTML += f(0.001) + '<br>'
document.getElementById('div').innerHTML += f(7) + '<br>'
<div id="div"></div>


2

Javascript:73/72文字

このアルゴリズムは不完全であり、この質問が小数点以下4桁に制限されているという事実を利用します。これは、質問を修正する目的でサンドボックスで提案したアルゴリズムの修正版です。ゼロから無限whileまでカウントしますがh*h*h<a、4桁の10進数の数字を処理する乗算と除算のトリックがあります。

function g(a){if(a<0)return-g(-a);for(h=0;h*h*h<1e12*a;h++);return h/1e4}

編集、4年後:Luis felipe De jesus Munozが示唆したように**、コードを使用することにより短くなりましたが、この答えは2014年にこの回答を書いたときに利用できませんでした。とにかく、それを使用して、余分な文字を剃ります:

function g(a){if(a<0)return-g(-a);for(h=0;h**3<1e12*a;h++);return h/1e4}

1
代わりに、1バイトをh*h*h実行h**3して保存することができます
ルイスフェリペデジェススムニョス

@LuisfelipeDejesusMunozこの回答は2014年のものです。この**演算子は2015年に提案され、2016年にECMAScript 7の一部として受け入れられ**ました。
ビクタースタフサ

1

Javascript-157文字

この関数:

  • 負の数を処理します。
  • 浮動小数点数を処理します。
  • 任意の入力番号に対して迅速に実行します。
  • JavaScriptの浮動小数点数に許可される最大精度を持ちます。
function f(a){if(p=q=a<=1)return a<0?-f(-a):a==0|a==1?a:1/f(1/a);for(v=u=1;v*v*v<a;v*=2);while(u!=p|v!=q){p=u;q=v;k=(u+v)/2;if(k*k*k>a)v=k;else u=k}return u}

Ungolfedの説明バージョン:

function f(a) {
  if (p = q = a <= 1) return a < 0 ? -f(-a)      // if a < 0, it is the negative of the positive cube root.
                           : a == 0 | a == 1 ? a // if a is 0 or 1, its cube root is too.
                           : 1 / f (1 / a);      // if a < 1 (and a > 0) invert the number and return the inverse of the result.

  // Now, we only need to handle positive numbers > 1.

  // Start u and v with 1, and double v until it becomes a power of 2 greater than the given number.
  for (v = u = 1; v * v * v < a; v *= 2);

  // Bisects the u-v interval iteratively while u or v are changing, which means that we still did not reached the precision limit.
  // Use p and q to keep track of the last values of u and v so we are able to detect the change.
  while (u != p | v != q) {
    p = u;
    q = v;
    k = (u + v) / 2;
    if (k * k * k > a)
      v=k;
    else
      u=k
  }

  // At this point u <= cbrt(a) and v >= cbrt(a) and they are the closest that is possible to the true result that is possible using javascript-floating point precision.
  // If u == v then we have an exact cube root.
  // Return u because if u != v, u < cbrt(a), i.e. it is rounded towards zero.
  return u
}

1

PHP、61

ニュートンの方法に基づいています。マイケルの答えのわずかに修正されたバージョン:

for($i=$x=1;$i++<99;)$x=(2*$x+$n/$x/$x)/3;echo round($x,14);

It works with negative numbers, can handle floating point numbers, and rounds the result to 4 numbers after the decimal point if the result is a floating point number.

Working demo


You can save two bytes with for($x=1;++$i<100;).... But using predefined variables as input is generally frowned upon. Better use $argv[1] or $argn.
Titus

1

Befunge 98 - Work in progress

This language does not support floating point numbers; this attempts to emulate them. It currently works for positive numbers that do not start with 0 after the decimal point (mostly). However, it only outputs to 2 decimal places.

&5ka5k*&+00pv
:::**00g`!jv>1+
/.'.,aa*%.@>1-:aa*

It works by inputting the part before the decimal point, multiplying that by 100000, then inputting the part after the point and adding the two numbers together. The second line does a counter until the cube is greater than the inputted number. Then the third line extracts the decimal number from the integer.

If anyone can tell me why the third line only divides by 100 to get the correct values, please tell me.

IOs:

27.0       3 .0
64.0       4 .0
1.0        1 .0
18.609625  2 .65
0.001      0 .1
7.0        1 .91

0.1        0 .1

1

Smalltalk, 37

credit goes to mniip for the algorithm; Smalltalk version of his code:

input in n; output in x:

1to:(x:=99)do:[:i|x:=2*x+(n/x/x)/3.0]

or, as a block

[:n|1to:(x:=99)do:[:i|x:=2*x+(n/x/x)/3.0].x]

1

GameMaker Language, 51 bytes

for(i=x=1;i++<99;1)x=(2*x+argument0/x/x)/3;return x

0

Haskell: 99C

Can't beat @mniip in cleverness. I just went with a binary search.

c x=d 0 x x
d l h x
 |abs(x-c)<=t=m
 |c < x=d m h x
 |True=d l m x
 where m=(l+h)/2;c=m*m*m;t=1e-4

Ungolfed:

-- just calls the helper function below
cubeRoot x = cubeRoot' 0 x x

cubeRoot' lo hi x
    | abs(x-c) <= tol = mid           -- if our guess is within the tolerance, accept it
    | c < x = cubeRoot' mid hi x      -- shot too low, narrow our search space to upper end
    | otherwise = cubeRoot' lo mid x  -- shot too high, narrow search space to lower end
    where
        mid = (lo+hi)/2
        cubed = mid*mid*mid
        tol = 0.0001

You can use an infix operator for d (like (l#h)x) to save a byte for each call. c then becomes id>>=(0#).
Esolanging Fruit

You can remove spaces around c < x.
Esolanging Fruit

You can use 1>0 instead of True.
Esolanging Fruit

0

J 28

*@[*(3%~+:@]+(%*~@]))^:_&|&1

Using Newtons method, finding the root of x^3 - X the update step is x - (x^3 - C)/(3*x^2), where x is the current guess, and C the input. Doing the maths on this one yields the ridiculously simple expression of (2*x+C/x^2) /3 . Care has to be taken for negative numbers.

Implemented in J, from right to left:

  1. | Take abs of both arguments, pass them on
  2. ^:_ Do until convergence
  3. (%*~@]) is C / x^2 (*~ y is equivalent to y * y)
  4. +:@] is 2 x
  5. 3%~ divide by three. This yields the positive root
  6. *@[ * positive_root multiplies positive root with the signum of C.

Test run:

   NB. give it a name:
   c=: *@[*(3%~+:@]+(%*~@]))^:_&|&1
   c 27 64 1 18.609625 3652264 0.001 7
3 4 1 2.65 154 0.1 1.91293

0

AWK, 53 bytes

{for(n=x=$1;y-x;){y=x;x=(2*x+n/x/x)/3}printf"%.4g",y}

Example usage:

$ awk '{for(n=x=$1;y-x;){y=x;x=(2*x+n/x/x)/3}printf"%.4g",y}' <<< 18.609625 
2.65$

Thanks go to @Mig for the JavaScript solution which this is derived from. It runs surprisingly quickly given that the for loop requires the iteration to stop changing.



0

Stax, 10 bytesCP437

╘♀┘A╕äO¶∩'

Run and debug online!

Explanation

Uses the unpacked version to explain.

gpJux*_+h4je
gp              Iterate until a fixed point is found, output the fix point
  Ju            Inverse of square
    x*          Multiplied by input
      _+h       Average of the value computed by last command and the value at current iteration
         4je    Round to 4 decimal digits

0

JAVA Solution

public BigDecimal cubeRoot(BigDecimal number) {

    if(number == null || number.intValue() == 0) return BigDecimal.ZERO;
    BigDecimal absNum = number.abs();
    BigDecimal t;
    BigDecimal root =  absNum.divide(BigDecimal.valueOf(3), MathContext.DECIMAL128);


    do {

        t = root;
        root = root.multiply(BigDecimal.valueOf(2))
                .add(absNum.divide(root.multiply(root), MathContext.DECIMAL128))
                .divide(BigDecimal.valueOf(3), MathContext.DECIMAL128);

    } while (t.toBigInteger().subtract(root.toBigInteger()).intValue() != 0);

    return root.multiply(number.divide(absNum), MathContext.DECIMAL128);
}

1
Welcome to PPCG! This is a code-golf challenge, which means the goal is to solve the challenge is as little code as possible (counted in bytes of the source file). You should show some effort towards optimising your solution towards that goal and include the byte count in your answer.
Martin Ender

0

Python Solution

def cube_root(num):
    if num == 0:
        return 0

    t = 0
    absNum = abs(num)
    root = absNum/3

    while (t - root) != 0:
        t = root
        root = (1/3) * ((2 * root) + absNum/(root * root))

    return root * (num / absNum)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.