Integrales definidas aproximadas usando sumas de Riemann

19

Las sumas de Riemann izquierda y derecha son aproximaciones a integrales definidas . Por supuesto, en matemáticas necesitamos ser muy precisos, por lo que nuestro objetivo es calcularlos con una serie de subdivisiones que se acercan al infinito, pero eso no es necesario para los propósitos de este desafío. En su lugar, debe intentar escribir el programa más corto, tomar entradas y proporcionar salidas a través de cualquiera de los métodos predeterminados , en cualquier lenguaje de programación , que haga lo siguiente:

Tarea

Dados dos números racionales y (los límites de la integral definida), un entero positivo , un booleano que representa izquierda / derecha y una función de recuadro negro , calcula la suma de Riemann izquierda o derecha (dependiendo de ) de , usando subdivisiones iguales .abnkf fkabf(x)dxn

Especificaciones de E / S

  • a y pueden ser números racional / de punto flotante o fracciones. b

  • k puede ser representado por dos valores distintos y consistentes, pero tenga en cuenta que no se le permite tomar funciones completas o parciales como entrada.

  • f es una función de recuadro negro. Citando la meta respuesta vinculada anteriormente,no se puede acceder al contenido (es decir, el código) de las funciones de recuadro negro, solo puede llamarlas (pasar argumentos si corresponde) y observar su salida. Si es necesario, incluya la información necesaria sobre la sintaxis que usa su idioma para que podamos probar su envío.

Como salida, debe proporcionar una fracción / punto flotante / racional que represente la suma de Riemann que se le solicita. Como se discutió en el pasado , la imprecisión de punto flotante puede ignorarse, siempre que su salida sea precisa al menos con tres decimales cuando se redondea al múltiplo más cercano de 1/1000 (por ejemplo, 1.4529999está bien en lugar de 1.453).

Especificaciones de matemáticas

  • f se garantiza que sea continua entrea y(sin saltos, sin agujeros, no hay asíntotas verticales).b

  • Hay tres casos posibles que debe manejar: (El resultado debe ser o sus equivalentes), o .a=b0a<ba>b

  • Si , la integral cambia su signo. Además, el sentido correcto de la integral en este caso es hacia .b<aa

  • Las áreas debajo del gráfico son negativas y las que están arriba del gráfico son positivas.

Ejemplos / Casos de prueba

La resolución no es óptima, porque tuve que reducirlos un poco, pero aún son legibles.

  • f(x)=2x+1,a=5,b=13,n=4 , k = derecha:

    2x + 1

    El resultado debe ser , porque el ancho de cada rectángulo es y el correspondiente las alturas son .152+192+232+272=168|ba|n=2f(7)=15,f(9)=19,f(11)=23,f(13)=27

  • f(x)=x,a=1,b=2.5,n=3 , k = izquierda:

    Raíz cuadrada

    La salida debe ser 1.8194792169 .

  • f(x)=3x+4+x25,a=12.5,b=2.5,n=10 , k = derecha:

    -3x + 4 + 1 / 5x ^ 2

    El valor de salida esperado es (4.055.456.457.057.257.056.455.454.052.25)=55.5 , porque la integral cambia de signo al voltear los límites ( b<a ) .

  • f(x)=94x+2x27,a=0,b=15,n=3 , k = izquierda:

    9-4x + 2 / 7x ^ 2

    Calculando nuestra suma de Riemann, obtenemos 13.5714285715 .

  • f(x)=6,a=1,b=4,n=2 , k = derecha - Salida:18 .

  • f(x)=x7+165x+1,a=7,b=7,n=4 , k = izquierda - Salida:0 .

  • f(x)=xsin(x1),a=0,b=1,n=500.385723952885505

Sr. Xcoder
fuente
3
Un agradecimiento especial: este desafío se ha publicado en el Sandbox , donde recibió valiosos comentarios de los usuarios202729 , AdmBorkBork y Leaky Nun .
Sr. Xcoder
Espero que las soluciones aquí ayuden a los estudiantes de Calc I por muchos años ...
Giuseppe
f(x) = x * sin(1 / x); a = 0; b = 1; n = 50; k = right — Output: 0.385723952885505. Note that sine uses radians here, but feel free to use degrees instead.Ahora que f (x) es un cuadro negro, ¿por qué es importante?
l4m2
@ l4m2 No importa mucho, solo quería que las personas supieran que no deberían preocuparse por esas cosas.
Sr. Xcoder
@Giuseppe No. Los métodos de los programas aquí son incluso peores que los métodos de las calculadoras de mano. [solo diciendo]
usuario202729

Respuestas:

8

R , 69 65 63 57 bytes

function(a,b,n,k,f,w=(b-a)/n)sum(sapply(a+w*(1:n-k),f))*w

Pruébalo en línea!

Toma las k=FALSEsumas de la mano derecha, aunque el enlace TIO ahora incluye alias para "izquierda" y "derecha" para facilitar su uso.

a+w*(1:n-k) genera puntos apropiados para la mano izquierda o derecha.

Luego se sapplyaplica fa cada elemento del resultado, que luego sumsubimos y multiplicamos por el ancho del intervalo (b-a)/npara obtener el resultado. Esto último también se ocupa de cualquier problema de señalización que podamos tener.

Giuseppe
fuente
4

SNOBOL4 (CSNOBOL4) , 127 bytes

	DEFINE('R(a,b,n,k,p)')
R	l =(b - a) / n
	i =1
l	R =R + eval(p '(a + l * (i - k))')
	i =lt(i,n) i + 1	:s(l)
	R =R * l :(return)

Pruébalo en línea!

Suponiendo que la función pse define en alguna parte, esto toma a,b,n,k,(name of p), con k=0para derecha e l=1izquierda.

catspaw's SNOBOL4+admite REALs pero no tiene funciones trigonométricas integradas. Sin embargo, supongo que uno podría llegar a una sinfunción razonable utilizando una serie de Taylor.

No estoy 100% seguro de que esta sea la forma "correcta" de pasar una función de recuadro negro en SNOBOL (que, que yo sepa, no tiene funciones de primera clase), pero me parece razonable.

Supongo que suponiendo que la función se defina como fsería más corta, ya que la línea lpodría ser

l	R =R + f(a + l * (i - k))

pero luego no se pasa como un argumento, que se siente un poco como "trampa".

Tenga en cuenta que el enlace TIO tiene una declaración :(e)posterior DEFINE, de modo que el código realmente se ejecutará correctamente.

Giuseppe
fuente
4

Julia 0.6 , 50 bytes

R(f,a,b,n,k)=(c=(b-a)/n;sum(f.(a+[k:n+k-1...]c))c)

Pruébalo en línea!

Se construye un rango normalizado, se recoge en un vector y luego se escala. Es necesario recopilar el rango en un vector [X...]para evitar el inexact erroral multiplicar el rango directamente por 0 cuando a=b. Del mismo modo, construir un rango directamente con :o range()no es posible cuando a=b.

El uso de k es muy similar a la solución de Guiseppe , con k=1for righty k=0for left.

Lucas
fuente
f.vectoriza fsobre sus argumentos?
Giuseppe
@Giuseppe: Exactamente. f.es una aplicación de elemento inteligente f.
LukeS
2

Haskell , 73 67 bytes

¡Gracias a H.PWiz y Bruce Forte por los consejos!

(f&a)b n k|d<-(b-a)/realToFrac n=d*sum(f<$>take n(drop k[a,a+d..]))

Pruébalo en línea!

Solución bastante sencilla.

kes 0para izquierda y 1para derecha.

Cristian Lupascu
fuente
1
Si está tomando n, no necesita subir ab
H.PWiz
2

Python 2 , 99 94 bytes

Un poco de una solución ingenua.

def R(f,a,b,n,k):s=cmp(b,a);d=s*(b-a)/n;return s*sum(d*f([0,a,b][s]+i*d)for i in range(k,n+k))

Pruébalo en línea!

mbomb007
fuente
Por alguna razón, pensé que teníamos que manejar la entrada entera. Gracias.
mbomb007
1

Jalea , 21 bytes

ƓḶ+Ɠ÷
IḢ×¢A+ṂɠvЀÆm×I

Pruébalo en línea!

Tomar a,bde argumentos, y

n
right
f

de stdin.


Si no está familiarizado con Jelly, puede usar Python para escribir la función de cuadro negro f:

f (x) = 2x + 1 ; a = 5; b = 13; n = 4; k = derecha

f (x) = √x ; a = 1; b = 2.5; n = 3; k = izquierda

f (x) = -3x + 4 + 1/5 * x 2 ; a = 12,5; b = 2.5; n = 10; k = derecha

f (x) = 9 - 4x + 2/7 * x 2 ; a = 0; b = 15; n = 3; k = izquierda

f (x) = 6 ; a = 1; b = 4; n = 2; k = derecha

f (x) = x * sin (1 / x) ; a = 0; b = 1; n = 50; k = derecha


Explicación:


ƓḶ+Ɠ÷     Helper niladic link.
Ɠ         First line from stdin. (n). Assume n = 4.
 Ḷ        Lowered range (unlength). Get [0, 1, 2, 3].
  +Ɠ      Add second line from stdin (k). Assume k = 1 (right).
            Get [1, 2, 3, 4].
    ÷     Divide by (n). Get [0.25,0.5,0.75,1].

IḢ×¢A+ṂɠvЀÆm×I   Main monadic link. Take input `[a, b]`, assume `a=2,b=6`.
IḢ                `a-b`. Get `-4`.
  ×¢              Multiply by value of niladic link above. Get `[-1,-2,-3,-4]`.
    A             Absolute value. Get `[1,2,3,4]`.
     +Ṃ           Add min(a, b) = 2. Get `[3,4,5,6]`.
        vЀ       For each number, evaluate with...
       ɠ            input line from stdin.
           Æm     Arithmetic mean.
             ×I   Multiply by `a-b`.

usuario202729
fuente
1

Perl 6 , 65 bytes

{my \d=($^b-$^a)/$^n;sum ($a,*+d...*)[($^k+^0>d)+ ^$n]».&^f X*d}

Pruébalo en línea!

Relativamente sencillo. La única complicación es manejar el a > bcaso, lo que hago al cambiar el indicador de entrada $^kcon 0 > d, que lo invierte cuando a > b.

Sean
fuente
0

APL (Dyalog Classic) , 37 bytes

{(a b n k)←⍵⋄ln÷⍨b-al×+/⍺⍺a+l×k+⍳n}

Pruébalo en línea!

APL NARS, 37 caracteres

La función tiene el argumento a la izquierda de la función, en el argumento numérico a la derecha abn k. En la pregunta k = izquierda aquí significa k = ¯1; k = aquí significa k = 0. Prueba:

  f←{(a b n k)←⍵⋄ln÷⍨b-al×+/⍺⍺a+l×k+⍳n}
  {1+2×⍵} f 5 13 4 0
168
  {√⍵} f 1 2.5 3 ¯1
1.819479217
  {4+(¯3×⍵)+0.2×⍵×⍵} f 12.5 2.5 10 0
55.5
  {9+(¯4×⍵)+7÷⍨2×⍵×⍵} f 0 15 3 ¯1
13.57142857
  {6-0×⍵} f 1 4 2 0
18
  {1+(165×⍵)+⍵*7} f 7 7 4 ¯1
0
  {⍵×1○÷⍵} f 0 1 50 0
0.3857239529
RosLuP
fuente
Los envíos se cuentan en bytes, no en caracteres. No recuerdo si NARS tiene una página de códigos personalizada (por lo que también sería de 37 bytes) o si usa UTF16.
Uriel
@Uriel Son 37 bytes en Dyalog APL classic, siga el enlace; posiblemente 35x2 bytes para Nars Apl ...
RosLuP
Entonces, ¿por qué lo escribes como NARS? ¿NARS incluso tiene dfnss? Por cierto, puedes descartar los primeros padres de 35 bytes
Uriel
APL NARS, 37 caracteres significa que también debería ejecutarse en NARS APL
RosLuP