Метод Ньютона за допомогою рекурсивних Квінс


32

Ваше завдання - обчислити квадратний корінь 2 за допомогою методу Ньютона - з невеликим поворотом. Ваша програма має обчислити ітерацію методом Ньютона та вивести вихідний код для наступної ітерації (яка повинна бути в змозі зробити те саме).

Метод Ньютона досить вичерпно описаний у Вікіпедії

Щоб обчислити квадратний корінь 2 методом Ньютона, ви:

  • Визначте f(x) = x^2 - 2
  • Визначте f'(x) = 2x
  • Визначити x[0](початкова здогадка)= 1
  • Визначте x[n+1] = x[n] - (f[n] / f'[n])

Кожна ітерація переміститься x [n] ближче до квадратного кореня з двох. Так -

  • x[0] = 1
  • x[1] = x[0] - f(x[0])/f'(x[0]) = 1 - (1 ^ 2 - 2) / (2 * 1) = 1.5
  • x[2] = x[1] - f(x[1])/f'(x[1]) = 1.5 - (1.5 ^ 2 - 2) / (2 * 1.5) = 1.416666667
  • x[3] = x[2] - f(x[2])/f'(x[1]) = 1.416666667 - (1.416666667 ^ 2 - 2) / (2 * 1.416666667) = 1.414215686
  • і так далі

Ваша програма:

  • Обчисліть, x[n]де nкількість разів запускається програма
  • Виведіть вихідний код у дійсну програму тією ж мовою, яка повинна обчислити x[n+1]та задовольнити однакові критерії цього питання.
  • Перший рядок вихідного коду повинен бути результатом обчислення, правильно прокоментованим. Якщо джерело вимагає чогось конкретного (наприклад, шебанг) ​​у першому рядку, результат може бути поставлений у другому рядку.

Зауважте, що

  • Ваша програма повинна використовувати початкові здогадки x[0] = 1
  • У стандартних лазівки застосовуються
  • Будь-які функції вбудованого живлення, квадратний корінь або функції xroot заборонені
  • Ваша програма не повинна приймати будь-які дані. Він повинен бути повністю самостійним.

Ваш бал - це розмір початкової програми в байтах UTF-8. Виграє найнижчий бал.


Чи потрібно визначати функції, чи можемо спростити їх написанням x = x-(x*x-2)/(2*x)?
Кайл Канос

Це спрощення для мене виглядає дійсним. Поки він виконує обчислення за методом Ньютона
lochok

Програма видає наближення чи просто вихідний код? Чи може вона взяти за свій внесок попереднє рішення?
Емілі

Він повинен вивести наближення (коментується) на першому рядку із вихідним кодом для наступної ітерації. Наближенню може передувати шебанг, якщо мова цього вимагає. Програма (а також програма, яку вона виробляє) не повинна приймати жодного введення.
lochok

Відповіді:


19

Загальна Лісп, 223 95 68 66

(#1=(lambda(x p)(format t"~S~%~S"p`(,x',x,(+(/ p 2)(/ p)))))'#1#1)

Тепер, коли я більш уважно прочитав постановку проблеми (спасибі, примо !), Я помітив, що перший рядок повинен бути результатом обчислення, а не те, що він повинен містити результат. Таким чином, я думаю, що мої попередні спроби не зовсім відповідали правилам. Цей повинен.

Приклад використання (SBCL 1.1.15):

$ sbcl --script nq.lisp | tee nq2.lisp
1
((LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 '(LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P))))) 3/2)
$ sbcl --script nq2.lisp | tee nq3.lisp
3/2
((LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 '(LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P))))) 17/12)
$ sbcl --script nq3.lisp | tee nq4.lisp
17/12
((LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 '(LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P))))) 577/408)
$ sbcl --script nq4.lisp | tee nq5.lisp
577/408
((LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 '(LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 665857/470832)
$ sbcl --script nq5.lisp | tee nq6.lisp
665857/470832
((LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 '(LAMBDA (X P) (FORMAT T "~S~%~S" P `(,X ',X ,(+ (/ P 2) (/ P)))))
 886731088897/627013566048)
$

Я здебільшого тестував CCL, але він працює аналогічно і SBCL, і CLISP.
jlahd

1
Це більше, як я очікував. +1
примо

17

Python - 60 байт

x=1.
o='x=%s\no=%r;print o%%(x/2+1/x,o)';print o%(x/2+1/x,o)

Я трохи спростив формулу, використовуючи такі підстановки:

  x-(x²-2)/(2x)
= (2x²)/(2x)-(x²-2)/(2x)
= (2x²-x²+2)/(2x)
= (x²+2)/(2x)
= (x+2/x)/2
= x/2+1/x

Сподіваюся, це не проблема.

Програма діє наступним чином:

$ python newton-quine.py
x=1.5
o='x=%s\no=%r;print o%%(x/2+1/x,o)';print o%(x/2+1/x,o)

$ python newton-quine.py
x=1.41666666667
o='x=%s\no=%r;print o%%(x/2+1/x,o)';print o%(x/2+1/x,o)

$ python newton-quine.py
x=1.41421568627
o='x=%s\no=%r;print o%%(x/2+1/x,o)';print o%(x/2+1/x,o)

$ python newton-quine.py
x=1.41421356237
o='x=%s\no=%r;print o%%(x/2+1/x,o)';print o%(x/2+1/x,o)

тощо.


Я не знаю, законно це чи ні, але ви можете скоротити свій початковий код до g="x=%s;o=%r;print o%%(x/2+1/x,o)";print g%(1.5,g)@ 50 символів.
cjfaure

@Trimsty Я думаю, що це трохи проблематично, що 1) він насправді не обчислює першу ітерацію, а 2) перший рядок не містить поточного результату. Як я розумію опис проблеми, і оригінальна програма, і пізніші покоління повинні задовольняти цим критеріям.
прим

13

CJam, 20 байт

1
{\d_2/1@/+p"_~"}_~

Спробуйте в Інтернеті.

Вихід

$ cjam <(echo -e '1\n{\d_2/1@/+p"_~"}_~'); echo
1.5
{\d_2/1@/+p"_~"}_~
$ cjam <(cjam <(echo -e '1\n{\d_2/1@/+p"_~"}_~')); echo
1.4166666666666665
{\d_2/1@/+p"_~"}_~
$ cjam <(cjam <(cjam <(echo -e '1\n{\d_2/1@/+p"_~"}_~'))); echo
1.4142156862745097
{\d_2/1@/+p"_~"}_~
$ cjam <(cjam <(cjam <(cjam <(echo -e '1\n{\d_2/1@/+p"_~"}_~')))); echo
1.4142135623746899
{\d_2/1@/+p"_~"}_~

Як це працює

1       " Push the initial guess.                                                 ";
{       "                                                                         ";
  \d    " Swap the code block with the initial guess and cast to Double.          ";
  _2/   " Duplicate the initial guess and divide the copy by 2.                   ";
  1@/   " Push 1, rotate the initial guess on top and divide.                     ";
  +p    " Add the quotients and print.                                            ";
  "_~"  " Push the string '_~'.                                                   ";
}       "                                                                         ";
_~      " Duplicate the code block (to leave a copy on the stack) and execute it. ";

2
Ну це вражає. +1
Кайл Канос

8

ECMAScript 6, 38 36

(f=x=>"(f="+f+")("+(x/2+1/x)+")")(1)
(f=x=>"(f="+f+")("+(x/2+1/x)+")")(1.5)
(f=x=>"(f="+f+")("+(x/2+1/x)+")")(1.4166666666666665)
(f=x=>"(f="+f+")("+(x/2+1/x)+")")(1.4142156862745097)
(f=x=>"(f="+f+")("+(x/2+1/x)+")")(1.4142135623746899)

JavaScript, 51

(function f(x){return "("+f+")("+(x/2+1/x)+")"})(1)

Для старих веб-переглядачів це те саме, що і вище.


1
Іноді я просто вражений тим, як простий javascript може зробити речі. +1
seequ

Це , здається, відсутній будь - якої продукції ( print, putstr, console.logі т.д.).
примо

@primo - коли JavaScript запускається в консолі, повернене значення автоматично надрукується.
Дерек 朕 會 功夫

@Derek 朕 會 功夫 Дуже багато мов можна запустити як REPL - це вираз, а не повна програма. Див.: Стандартні «лазівки», які вже не є смішними .
primo

1
@Derek 朕 會 功夫 Опис проблеми спеціально запитує програму - в декількох місцях. Поставлена ​​програма нічого не робить. Свідок: i.stack.imgur.com/Te7Vf.png Вищенаведене - це вираз, який оцінює вираз. У цьому є своя заслуга, але це не програма.
прима

6

Луа 129

Напевно, занадто довго, але Lua quine смокче, тому що вкладене [[ ]]є застарілою особливістю. Але це працює незалежно:

x=1.0;x=x/2.+1./x;l=[[io.write('x=',x,';x=x/2.+1./x;l=[','[',l,']','];',l)]];io.write('x=',x,';x=x/2.+1./x;l=[','[',l,']','];',l)

Трохи приємніше бачити, якщо ви додаєте нові рядки замість кольорових знаків:

x=1.0
x=x/2.+1./x
l=[[io.write('x=',x,'\nx=x/2.+1./x\nl=[','[',l,']','];',l)]];io.write('x=',x,'\nx=x/2.+1./x\nl=[','[',l,']','];',l)

4

J - 102 88 байт

Це настільки жахливо, як і я роблю quines (я, мабуть, перегляну це, коли отримаю кращі ідеї). Поплавці J обмежені 5 знаками після коми, але замінивши перший рядок на x=:1xнього було б дробом з нескінченною точністю.

Edit 1: I got better idea. Also added the explanation.

x=:1
((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'x=:((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'''

Перші кілька повторень:

x=:1.5
((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'x=:((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'''

x=:1.41667
((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'x=:((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'''

x=:1.41422
((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'x=:((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'''

Пояснення

((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'x=:((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:)'''
((3&{.,[:":(x%2)+1%x"_),:3&}.,],{:,{:) The quine-function
                         3&}.,],{:,{:  Build the second row
                         3&}.          Get everything but the first 3 characters from the string
                             ,]        Get the whole string and concat
                               ,{:     Get the last item (') and concat
                                  ,{:  -||-
 (3&{.,[:":(x%2)+1%x"_)                Build the first row
       [:":(x%2)+1%x"_                 Calculate x/2 + 1/x (stolen from Pythoneer) and stringify
  3&{.                                 Take the first 3 characters from the string (x=:)
      ,                                Concatenate 'x=:' and the result
                       ,:              Concatenate the two rows

1
Я насправді люблю, наскільки ця програма проста (для серйозних).
seequ

Якщо я отримаю більше часу, я побачу, чи зможу я змінити вищезазначене для Kona.
Кайл Канос

@KyleKanos Принаймні обертання цифр було досить схожим, але я не знаю Кони. Удачі! :)
seequ

1%xте саме, що %x. Замість цього (x%2)+1%xможна зробити (%&2+%)x.
Conor O'Brien

3

Рубі, 65

x=1.0
puts"x=#{x/2+1/x}",<<'1'*2,1
puts"x=#{x/2+1/x}",<<'1'*2,1
1

Як це занадто часто трапляється, це майже прямий порт рішення Python.

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