Обчисліть кубик кореня числа


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
Судячи з ваших тестових випадків, я припускаю, що програмі потрібно мати справу лише з реальними цифрами?
користувач12205

@ace додати комплекс і міняю 2 букви в моєму коді;)
йо »

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

Хаскелл - 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-й кореневі водорості протягом останньої години, і я тільки що дійшов до того ж результату. Браво.
прим

@primo я одразу згадав усі алгоритми наближення кореневих кореневищ, і після відмови від серії Taylor / Maclaurin в APL я використав це.
mniip

Використовуючи метод Ньютона, який я отримав x=(2*x+n/x/x)/3, чи можете ви пояснити, чому ви можете використовувати x=(x+n/x/x)/2? Він конвертується повільніше, але я не можу пояснити, чому він конвергується ...
Майкл М.

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

Я вважаю, що ви використовуєте оператора, який може підняти число до потужності.
користувач12205

ах добре, правильно, відредагований
йо »

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

@Mechanicalsnail Дякую Я сподіваюся , що це очевидно, що я роблю , це свого роду спад: D Однак, якщо expдозволено, я до 12 років, а не по-дурному взагалі :)
йо »

Враховуючи, що expце коротке значення для "експоненціальної функції", яка є "функцією, значення якої є постійною, підвищеною до сили аргументу, особливо функції, де константа є е.", І "Не застосовуються методи / оператори, які може підняти число до потужності ", expзаборонено.
mbomb007

5

Пітон - 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

1
@justhalf Я думаю, що це метод наближення Ньютона в основному.
йо

До речі, не буде працювати на0
йо »

Не вдається -2, вибачте за це.
йо

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')
Luis felipe De jesus Munoz

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дає NANPHP 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

Бачачи, що у 16 символах є відповідь J , я повинен бути дуже жахливим у 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 було надзвичайно хорошою ідеєю. Конструюючи питання, я думаю, що законно зробити цей метод замість функціонуючого класу 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)бути дозволено правилами: - /
йо »

Експоненціальна функція: "функція, значення якої є постійною, підвищеною до сили аргументу , особливо функції, де постійною є е". ... "Немає використання методів / операторів, які можуть підняти число до потужності"
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 байт
Luis felipe De jesus Munoz

@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на отримання правильних значень, будь ласка, скажіть мені.

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 для алгоритму; Версія його коду:

введення в n; вихід у х:

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

Безголівки:

-- 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), де 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 розмножується позитивним корінцем із ситумом С.

Пробіг:

   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

Рішення JAVA

загальнодоступний BigDecimal cubeRoot (BigDecimal число) {

    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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.