实现欧拉方法


9

这个挑战的目标是使用欧拉方法来近似形式为f (n)(x)= c的微分方程的解。

输入将是一个整数列表,其中第n个值代表f (n)(0)的值。第一个整数是f(0),第二个整数是f'(0),依此类推。此列表中的最后一个整数是常数,并且将始终保持不变。

作为输入还提供了一个正(非零)整数x,它表示目标值(您正在尝试估计f(x))。欧拉方法的步长始终为1。因此,您将总共需要执行x步。

如果你是unfamliar欧拉的方法,这里是与输入的解释一个详细的例子[4, -5, 3, -1]X = 8。

x       f(x)      f'(x)     f''(x)    f'''(x)
0          4         -5          3         -1
1   4-5 = -1  -5+3 = -2   3-1 =  2         -1
2  -1-2 = -3  -2+2 =  0   2-1 =  1         -1
3  -3+0 = -3   0+1 =  1   1-1 =  0         -1
4  -3+1 = -2   1+0 =  1   0-1 = -1         -1
5  -2+1 = -1   1-1 =  0  -1-1 = -2         -1
6  -1+0 = -1   0-2 = -2  -2-1 = -3         -1
7  -1-2 = -3  -2-3 = -5  -3-1 = -4         -1
8  -3-5 = -8

本质上,生成的表中的每个单元都是其上方的单元与上方和右侧的单元之和。因此,f(a)= f(a-1)+ f'(a-1); f'(a)= f'(a-1)+ f''(a-1); 和f''(a)= f''(a-1)+ f'''(a-1)。最终答案是f(8)≈-8。††

输入列表将总是包含2层或更多的元件,所有这些都将具有绝对值小于10 X ≥1也有保证。输出是单个整数,即f(x)的近似值。输入可以按任意顺序进行(在x之前的列表或在列表之前的x)。如果需要,x也可以是列表的第一个或最后一个元素。

测试用例:

[4, -5, 3, -1], x = 8 => -8
[1, 2, 3, 4, 5, 6], x = 10 => 3198
[1, 3, 3, 7], x = 20 => 8611
[-3, 3, -3, 3, -3, 3, -3, 3, -3], x = 15 => -9009
[1, 1], x = 1 => 2

†:值得注意的是,在这种情况下使用近似方法实际上是愚蠢的。但是,为解决这一挑战,选择了最简单的功能。

††:实际值恰好为-25⅓,这会使该近似值合格为“不是很好”。



Answers:


3

Haskell,38个字节

l%n|n<1=l!!0|m<-n-1=l%m+tail(l++[0])%m

在线尝试!

从39个字节改进:

l%0=l!!0
l%n=l%(n-1)+tail(l++[0])%(n-1)

递归地表示输出l%n。向上移动对应于递减n,向右移动对应于将tail l所有列表元素向左移动一格。因此,输出l%n为上面的值l%(n-1),加上上面和右边的值(tail l)%(n-1)

基本情况n==0是采用第一个列表元素。

理想情况下,由于多项式的导数最终变为零,所以在右边用无限多个零填充输入。0当我们使用时,可以通过添加来模拟这一点tail

奇怪的替代41:

(iterate(\q l->q l+q(tail l++[0]))head!!)


3

果冻6 5字节

Ḋ+$¡Ḣ

在线尝试!

-1字节感谢@Doorknob

说明

Ḋ+$¡Ḣ  - Main dyadic link. First input list, second x
       - (implicit) on the previous iteration (starting at input list)
Ḋ      - Dequeue. e.g. [-5,3,-1]
 +     - Add this to
       - (implicit) the previous iteration. e.g. [4+(-5),-5+3,3+(-1),-1+0]
  $¡   - apply this successively x times
    Ḣ  - get the first element from the resultant list

3

Brachylog13 12字节

{,0s₂ᶠ+ᵐ}ⁱ⁾h

在线尝试!

怎么运行的

{,0s₂ᶠ+ᵐ}ⁱ⁾h
{       }ⁱ⁾   iterate the previous predicate
              to the array specified by first element of input
              as many times as the second element of input
           h  and get the first element

              example input to predicate: [4, _5, 3, _1]
 ,0           append 0: [4, _5, 3, _1, 0]
   s₂ᶠ        find all substrings with length 2:
              [[4, _5], [_5, 3], [3, _1], [_1, 0]]
      +ᵐ      "add all the elements" mapped to each subarray:
              [_1, _2, _2, _1]

以前的13字节解决方案

{b,0;?z+ᵐ}ⁱ⁾h

在线尝试!

怎么运行的

{b,0;?z+ᵐ}ⁱ⁾h
{        }ⁱ⁾   iterate the previous predicate
               to the array specified by first element of input
               as many times as the second element of input
            h  and get the first element

               example input to predicate: [4, _5, 3, _1]
 b             remove the first element: [_5, 3, _1]
  ,0           append 0: [_5, 3, _1, 0]
    ;?         pair with input: [[_5, 3, _1, 0], [4, _5, 3, _1]]
      z        zip: [[_5, 4], [3, _5], [_1, 3], [0, _1]]
       +ᵐ      "add all the elements" mapped to each subarray:
               [_1, _2, _2, _1]

2

Mathematica,32个字节

#&@@Nest[#+Rest@#~Append~0&,##]&
                               &  make a pure function
    Nest[                 &,##]   call inner function as many times as specified
           Rest@#                 drop the first element of the list
                 ~Append~0        and add a 0 to get [b,c,d,0]
         #+                       add original list to get [a+b,b+c,c+d,d]
#&@@                              take the first element after x iterations

2

Python80 58字节

喜欢这个挑战的数学。

f=lambda a,x:x and f(map(sum,zip(a,a[1:]+[0])),x-1)or a[0]

工作原理(仅适用于python 2):

f=lambda a,x:                                              - new lambda function
             x and                                         - iterate itself x times
                     map(sum,zip(a,a[1:]+[0]))             - e.g; f(a) = f(a-1) + f'(a-1)
                   f(                         ,x-1)        - iterate new array into itself
                                                   or a[0] - return first element

在线尝试!

100字节交替使用帕斯卡三角形

from math import factorial as F
f=lambda a,x:sum([(a+[0]*x)[i]*F(x)/(F(x-i)*F(i))for i in range(x)])

工作原理(适用于python 2和3):

sum([                                                ]) - take the sum of array
     (a+[0]*x)                                        - append x zeros
              [i]*F(x)/(F(x-i)*F(i))                  - multiply each element by x choose i
                                    for i in range(x) - do this for every element

该式的工作方式是行的系数映射x帕斯卡三角形到阵列上。帕斯卡三角形的每个元素由行和索引的选择功能确定。这个新数组的总和等于处的输出x。它也很直观,因为牛顿法的迭代过程(如示例所示)与帕斯卡三角形的构造完全一样。

在线尝试!

非常感谢ovs通过将循环转换为递归函数来减少22个字节


是一个改进的版本。我将for循环转换为递归函数
ovs

啊,伟大的想法@ovs
引力

甚至更短 请注意,它仅适用于python2
ovs'5

1

Haskell,52个 45字节

l#n=iterate(zipWith(+)=<<tail.(++[0]))l!!n!!0

用法示例:[-3,3,-3,3,-3,3,-3,3,-3] # 15-> -9009在线尝试!

怎么运行的

iterate(      )l          -- apply the function again and again starting with l
                          -- and collect the intermediate results in a list
                          -- the function is
          (++[0])         -- append a zero 
  zipWith(+)=<<tail       -- and build list of neighbor sums
                     !!0  -- take the first element from
                  !!n     -- the nth result

编辑:@xnor保存7个字节。谢谢!


我认为迭代函数可以是zipWith(+)=<<tail.(++[0]),即预先固定列表,而不是之后。
xnor

@xnor:是的,这样可以节省很多字节。谢谢!
nimi

我只是不能=<<
全神贯注

@flawr:=<<在函数上下文中使用,并定义为:(=<<) f g x = f (g x) x。在这里,我们使用=<<infix:(f =<< g) xf = zipWith(+)g = tail,将其转换为zipWith(+) (tail x) x
nimi

谢谢您的详细解释,我还没有意识到monad的功能!
瑕疵

1

CJam,12个字节

q~{_(;.+}*0=

在线尝试!

说明

该代码直接实现挑战中描述的过程。

q~            e# Read input and evaluate. Pushes the array and the number x
  {     }*    e# Do the following x times
   _          e# Duplicate array
    (;        e# Remove first element
      .+      e# Vectorized sum. The last element in the first array, which doesn't 
              e# have a corresponding entry in the second, will be left as is
          0=  e# Get first element. Implicitly display



1

实际上,7个字节

;lr(♀█*

在线尝试!

怎么运行的

;lr(♀█*  input:
         8, [4, -5, 3, -1]
         top of stack at the right
;        duplicate
         8, [4, -5, 3, -1], [4, -5, 3, -1]
 l       length
         8, [4, -5, 3, -1], 4
  r      range
         8, [4, -5, 3, -1], [0, 1, 2, 3]
   (     rotate stack
         [4, -5, 3, -1], [0, 1, 2, 3], 8
    ♀█   map "n choose r"
         [4, -5, 3, -1], [1, 8, 28, 56]
      *  dot product
         -8

1

八度,42字节

@(a,x)conv(a,diag(flip(pascal(x+1))))(x+1)

这定义了一个匿名函数。在线尝试!

说明

可以通过使用反复卷积输入数组和结果数组来计算解决方案[1, 1]。但是卷积两次,或三次,或...与[1, 1]对应于卷积一次[1, 2 ,1],或[1, 3, 3, 1],或...;也就是说,带有一排Pascal三角形。这是作为Pascal阶矩阵的对角线获得的x+1


0

JavaScript(ES6),41个字节

f=(a,x,[b,...c]=a)=>x--?f(a,x)+f(c,x):b|0

@xnor出色的Haskell答案端口。以前的47字节解决方案。

f=(a,x)=>x--?f(a.map((e,i)=>e+~~a[i+1]),x):a[0]


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.