Вычислить кубический корень из числа


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


блин, если бы вы разрешали только цифры с точным кубом, я бы получил хороший гольф
yo '

1
Судя по вашим тестам, я предполагаю, что программе нужно иметь дело только с реальными числами?
user12205

@ace добавить сложный, и я изменяю 2 буквы в моем коде;)
yo '

2
Является ли строгим требованием округление до 4 цифр после десятичной точки? Или это может быть что-то вроде «вам не нужно показывать более 4 цифр после десятичной точки»?
Виктор Стафуса

Со ссылкой на мой ответ, используя Exp (ln (x) / 3) (и несколько его клонов), пожалуйста, уточните, разрешен ли Exp. Я предполагаю, что pow (x, 1/3) нет (хотя технически это не функция кубического корня.)
Level River St

Ответы:


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

Не один из лучших многословных переводов, так как есть диадическая вилка и ~право в конце.


19

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

:+Оператор должен читаться как «плюс I раз»


1
Это заслуживает +1. В течение последнего часа я проводил рефакторинг обобщенных n-ых корневых algs и только сейчас достиг того же результата. Браво.
Примо

@primo Я сразу вспомнил все алгоритмы аппроксимации n-го корня, и после отказа от ряда Тейлора / Маклорина в APL я использовал это.
Мниип

Используя метод Ньютона, который я получил x=(2*x+n/x/x)/3, вы можете объяснить, почему вы можете использовать x=(x+n/x/x)/2? Оно сходится медленнее, но я не могу объяснить, почему оно сходится ...
Майкл М.

@ Майкл, потому что если ты возьмешь x=cbrt(n), то x=(x+n/x/x)/2это правда. Так ли это верно для вашего выражения
mniip

@ Майкл, я попал туда так: 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 '

6
+1 за монументально глупый алгоритм, который все еще удовлетворяет требованиям.
Механическая улитка

@Mechanicalsnail Спасибо. Надеюсь, очевидно, что то, что я делаю, является своего рода рецессией: D Однако, если 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

Как это работает?
полугодие

1
@justhalf Я думаю, что это в принципе метод приближения Ньютона.
лет '22

Кстати, терпит неудачу0
лет '22

Не удается -2, извините за это.
лет '22

3
@plg Описание проблемы запрещает использование любой экспоненциальной функции, в противном случае v**(1/.3)это был бы верный победитель.
Примо

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) 

На один символ короче: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);

Что произойдет, если он попытается вычислить кубический корень из нуля?
Виктор Стафуса

Он просто выведет «0» (благодаря оператору подавления ошибок - «@»).
Разван

1
0.0001можно заменить 1e-4и 0.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используя ряды Тейлора / Маклорина.

Образцы прогонов:

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

Ява, 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 итераций.

Вот не-Голфед:

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.0на 1e4, уменьшая 6 символов. Класс не должен быть общедоступным, поэтому вы можете уменьшить еще на 7 символов. Таким образом, он будет уменьшен до 185 символов.
Виктор Стафуса

Действительно ли актерский состав в конце действительно необходим? Это не для меня.
Виктор Стафуса

@Victor Спасибо за хороший взгляд, использование E-обозначения для 10000.0 double было потрясающе хорошей идеей. По структуре вопроса я думаю, что вполне закономерно сделать этот метод вместо функционирующего класса Cli, что значительно уменьшит размер. С Java я не думал, что у меня есть шанс, поэтому я ошибся на стороне функционала.
md_rasler

Добро пожаловать в CodeGolf! Не забудьте добавить в ответ объяснение, как это работает!
Джастин

@Quincunx, спасибо, сделал рекомендуемые изменения.
md_rasler

2

TI-Basic, 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)чтобы быть разрешенным правилами: - /
'22

Экспоненциальная функция: «функция, значение которой является константой, возведенной в степень аргумента , особенно функция, в которой константа равна e». ... «Не использовать методы / операторы, которые могут возвести число в степень»
mbomb007

Спасибо за улов @ mbomb007, я написал этот ответ более 3-х лет назад и сейчас исправлю его.
Timtech

2

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 цифрами после десятичной точки. Это модифицированная версия алгоритма, который я предложил в песочнице для доработки вопроса. Он отсчитывает от нуля до бесконечности 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}

Редактирование, 4 года спустя: по предложению Луиса Филипе Де Иисуса Муньоса, использование **кода короче, но эта функция была недоступна еще в 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 байт
Луис Фелипе Де Иисус Муньос

@LuisfelipeDejesusMunoz Этот ответ с 2014 года. **Оператор был предложен в 2015 году и был принят как часть ECMAScript 7 в 2016 году. Итак, в то время, когда я писал это, **языка не было.
Виктор Стафуса

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

Он работает с отрицательными числами, может обрабатывать числа с плавающей запятой и округляет результат до 4 чисел после десятичной точки, если результатом является число с плавающей запятой.

Рабочая демонстрация


Вы можете сохранить два байта с помощью for($x=1;++$i<100;).... Но использование предопределенных переменных в качестве входных данных обычно не одобряется . Лучше использовать $argv[1]или $argn.
Тит

1

Befunge 98 - работа в процессе

Этот язык не поддерживает числа с плавающей запятой; это пытается подражать им. В настоящее время он работает для положительных чисел, которые не начинаются с 0десятичной запятой (в основном). Тем не менее, он выводит только до 2 десятичных знаков.

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

Он работает путем ввода части перед десятичной запятой, умножения ее на 100000, затем ввода части после запятой и сложения двух чисел. Вторая строка делает счетчик, пока куб не станет больше введенного числа. Затем третья строка извлекает десятичное число из целого числа.

Если кто-то может сказать мне, почему третья строка делится только 100для получения правильных значений, пожалуйста, сообщите мне.

ИО:

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 его кода:

ввод в п; вывод в х:

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]


0

Haskell: 99C

Не могу победить @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

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

Вы можете использовать инфиксный оператор для d(как (l#h)x), чтобы сохранить байт для каждого вызова. cтогда становится id>>=(0#).
Esolanging Fruit

Вы можете удалить пробелы вокруг c < x.
Esolanging Fruit

Вы можете использовать 1>0вместо True.
Esolanging Fruit

0

J 28

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

Используя метод Ньютонов, находим корень x^3 - Xшага обновления x - (x^3 - C)/(3*x^2), где х - текущее предположение, а С - вход. Математика на этом дает нелепо простое выражение (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

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

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
Добро пожаловать в PPCG! Это задача кода-гольфа , поэтому цель состоит в том, чтобы решить задачу как можно меньше кода (считается в байтах исходного файла). Вы должны приложить некоторые усилия для оптимизации вашего решения для достижения этой цели и включить количество байтов в ваш ответ.
Мартин Эндер

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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.