计算数字的立方根


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...)


该死的,如果您只允许有精确立方的数字,那我将打一场不错的高尔夫球
2014年

1
从您的测试用例来看,我认为该程序只需要处理实数?
user12205 2014年

@ace add complex,我在代码中更改了2个字母;)

2
是否强烈要求小数点后四舍五入到4位数字?还是类似“您不需要在小数点后显示多于4位数字”之类的内容?
Victor Stafusa 2014年

关于我使用Exp(ln(x)/ 3)的答案(及其几个​​克隆),请澄清是否允许使用Exp。我认为pow(x,1/3)不是(即使从技术上讲它不是立方根函数。)
Level River St

Answers:


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

这不是最好的罗word翻译之一,因为它有一个二叉形的叉和一个~右叉。


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

此外,如果您导入Data.Complex,它甚至可以处理复数,它会返回数字的根之一(有3个):

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

:+运营商应该读作“加的时间”


1
这值得+1。在过去的一个小时中,我一直在重构广义的第n个根算法,而我刚得到了相同的结果。太棒了
primo 2014年

@primo我立即想起了所有第n个根近似算法,在放弃了APL中的Taylor / Maclaurin系列后,我使用了它。
mniip 2014年

使用我得到的牛顿法x=(2*x+n/x/x)/3,你能解释为什么可以使用x=(x+n/x/x)/2吗?它收敛较慢,但我无法解释为什么会收敛...
Michael M.

@Michael,因为如果您接受x=cbrt(n),那么它x=(x+n/x/x)/2是正确的。您的表情也是如此
-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

嗯,对了,已编辑
yo'14

6
+1仍然满足要求的笨拙算法。
机械蜗牛

@Mechanicalsnail谢谢。我希望这是显而易见的是什么,我做的是一种衰退的:d但是,如果exp允许,我到12,并在所有:)不是太傻了
哟,

考虑到这exp是“指数函数”的缩写,“指数函数”的值是一个常数,该常数是自变量的幂,尤其是常数为e的函数。”,并且“没有使用任何方法/运算符可以将数字加为幂”,这exp是不允许的。
mbomb007 '17

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

这是如何运作的?
justhalf 2014年

1
@justhalf我认为这基本上是牛顿的近似方法。
2014年

顺便说一句,失败了0
2014年

失败-2,抱歉。
2014年

3
@plg问题描述禁止使用任何指数函数,否则v**(1/.3)肯定是赢家。
2014年

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)return 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) 

缩短一个字符: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);

如果尝试计算零的立方根会怎样?
Victor Stafusa 2014年

它将仅输出“ 0”(由于错误抑制运算符-“ @”)。
Razvan 2014年

1
0.0001可以被替换为1e-40.00001通过1e.5
ComFreek

这需要PHP <7(0/0给出NAN在PHP 7)。$i=0;是不必要的(-5个字节。如果不是,for则将节省一个字节。)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;

计算基于牛顿法

计算方式


2

APL-31

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

使用的事实cbrt(x)=e^(ln(x)/3),而不是进行幼稚的幂运算,而是e^x使用Taylor / 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

看到有16个字符的J答案,我在APL一定很糟糕...


2

Java中,207 182 181

有时候,当我打高尔夫球时,我会喝很多啤酒,打得真的很糟糕

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变量重命名为z,减少6个字符。您可以删除for循环主体中的空格和花括号,减少3个字符。您可以替换10000.01e4,减少6个字符。该类不需要是公共的,因此您可以减少更多7个字符。这样,它将减少到185个字符。
Victor Stafusa 2014年

最后的演员真的必要吗?它不适合我。
Victor Stafusa 2014年

@Victor感谢您的关注,将E表示法用于10000.0 double是一个了不起的好主意。通过问题的设计,我认为将其用作方法而不是起作用的cli类是合法的,这将大大减小尺寸。使用Java,我认为我没有机会,所以我在功能方面犯了错误。
md_rasler 2014年

欢迎来到CodeGolf!不要忘了添加有关此工作原理的答案!
贾斯汀

@Quincunx,谢谢,进行了建议的更改。
md_rasler 2014年

2

TI基本(26 24字节)

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

那直接使用^运算符,不是吗。这是规则所禁止的
mniip

@mniip:e^TI-83系列上是否只有一个操作员?我不记得了 无论哪种方式,都违反了规则的精神。
机械蜗牛

@Mechanicalsnail我说没关系。在大多数语言中,您可以这样做,exp(ln(x)/3)或者e^(ln(x/3))如果您允许这两种语言中的任何一种。但不知何故,我明白exp(ln(x)/a)的太多等同于x^(1/a)到规则允许: - /
哟,

指数函数:“一个其值是一个常数的函数,该常数升为自变量的幂,尤其是常数为e的函数。” ...“不使用可以将数字提高为幂的方法/运算符”
mbomb007 '17

感谢@ mbomb007的帮助,我在3年前就写了这个答案,现在我将对其进行修复。
Timtech '17

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个字符

该算法很la脚,并且利用了这个问题被限制在小数点后4位这一事实。这是我在沙箱中建议的算法的修改版本,目的是解决问题。它从零开始计数到无穷大,而h*h*h<a只是通过乘法和除法来处理4位十进制数字精度。

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

四年后编辑:正如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
相反,h*h*h您可以h**3保存1个字节
Luis felipe De耶稣Munoz,

@LuisfelipeDejesusMunoz该答案来自2014年。该**运算符于2015年提出,并于2016年被ECMAScript 7接受。因此,在我写这篇文章的时候,**该语言还没有。
Victor Stafusa

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}

取消解释的版本:

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

Befunge 98-进行中

该语言不支持浮点数。试图模仿它们。目前,它适用于0以小数点后的数字开头(大多数情况下)的正数。但是,它仅输出到小数点后两位。

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

通过在小数点前输入部分100000,然后乘以,然后在小数点后输入部分,然后将两个数字相加,即可工作。第二行进行计数,直到多维数据集大于输入的数字为止。然后,第三行从整数中提取十进制数。

如果有人可以告诉我为什么第三行只除以100得到正确的值,请告诉我。

IO:

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岁

该算法归功于mniip;他的代码的Smalltalk版本:

输入n; 在x中输出:

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

或者,作为一个块

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

1

GameMaker语言,51字节

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

0

Haskell:99℃

不能击败@mniip。我只是进行了二进制搜索。

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

取消高尔夫:

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

您可以将infix运算符用于d(如(l#h)x)为每个调用保存一个字节。c然后成为id>>=(0#)
硕果累累

您可以删除周围的空格c < x
硕果累累

您可以使用1>0代替True
硕果累累

0

第28章

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

使用牛顿法,找到x^3 - X更新步骤的根是x - (x^3 - C)/(3*x^2),其中x是当前猜测,C是输入。在这个数学上进行数学运算得出的简直荒谬(2*x+C/x^2) /3。必须注意负数。

从右到左用J实现:

  1. | 拿两个论点的绝对值,传递给他们
  2. ^:_ 做直到收敛
  3. (%*~@])C / x^2*~ y等于y * y
  4. +:@]2 x
  5. 3%~除以三。这产生了积极的根源
  6. *@[ * positive_root 将正根乘以C的符号。

测试运行:

   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个字节

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

用法示例:

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

感谢@Mig提供的JavaScript解决方案。考虑到for循环需要迭代来停止更改,因此它运行起来出奇地快。


0

C,69字节

i;float g(float x){for(float y=x;++i%999;x=x*2/3+y/3/x/x);return x;}

只是牛顿方法的另一种实现。在线尝试!


0

Stax,10 位元组CP437

╘♀┘A╕äO¶∩'

在线运行和调试!

说明

使用解压后的版本进行解释。

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解决方案

公共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
欢迎来到PPCG!这是一个代码挑战,这意味着目标是解决挑战,即尽可能减少代码(以源文件的字节数计)。您应该为实现该目标而优化解决方案,并在回答中包括字节数。
马丁·恩德

0

Python解决方案

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.