Interpolation polynomiale

12

Écrivez un programme qui effectue une interpolation polynomiale à l' aide de vrais nombres rationnels de précision arbitraire. L'entrée ressemble à ceci:

f (1) = 2/3
f (2) = 4/5
f (3) = 6/7
...

Vous pouvez supposer qu'il y a exactement un espace avant et après le =signe, tous les nombres sont soit des fractions soit des entiers. Vous pouvez également supposer que toutes les fractions de l'entrée sont déjà irréductibles.

Aucune vérification d'erreur n'est nécessaire, vous pouvez supposer que l'entrée est valide et qu'aucun x n'est doublé dans le f (x).

La sortie doit être sous une forme compatible LaTeX, le code LaTeX émis doit donner la même représentation graphique que la sortie donnée ici.

f (x) = 123x ^ 2 + \ frac {45} {2} x + \ frac {7} {4}

La fraction doit être réduite autant que possible, par exemple. quelque chose comme \frac{2}{4} n'est pas autorisé. Si le nombre est entier, n'utilisez pas de fraction.

Règles spéciales:

Votre programme devrait ...

  • travailler pour des polynômes jusqu'au degré 12
  • terminer en moins de 1 minute pour une entrée raisonnable
  • ne pas utiliser de fonctions qui font tout le calcul pour vous
  • produire le polynôme du plus petit degré possible

Testcases:

Les cas de test donnés sont juste pour clarification. Votre programme devrait donner un résultat correct pour toutes les entrées correctes.

Contribution

f (1) = 2/3
f (2) = 4/5
f (3) = 6/7

Production

f (x) = - \ frac {4} {105} x ^ 2
       + \ frac {26} {105} x
       + \ frac {16} {35}

Contribution

f (-12) = 13/2
f (5/3) = 3/5
f (13) = -6
f (1/5) = -3/4

Production

f (x) = - \ frac {2186133} {239455744} x ^ 3
       + \ frac {2741731} {149659840} x ^ 2
       + \ frac {26720517} {29201920} x
       - \ frac {279464297} {299319680}

Contribution

f (4/3) = 617/81
f (2) = 20/3
f (-8/3) = 6749/81
f (-5) = 7367/12
f (0) = 23/3

Production

f (x) = \ frac {1} {2} x ^ 4
     - 2x ^ 3
     + \ frac {7} {4} x ^ 2
     + \ frac {23} {3}

Contribution

f (0) = 5
f (1) = 7
f (2) = 9
f (3) = 11
f (4) = 13

Production

f (x) = 2x
     + 5

Contribution

f (1/2) = -1/2
f (-25) = -1/2
f (-54/12) = -1/2

Production

f (x) = - \ frac {1} {2}
FUZxxl
la source
Pourquoi parlez-vous de nombres réels si vous n'utilisez que des nombres rationnels?
Joey
Pardon. Mon anglais est pauvre. Oui, utilisez uniquement des nombres rationnels. Les résultats doivent être exacts.
FUZxxl
Dans le premier test, les points ( ...) font-ils vraiment partie de l'entrée?
Eelvex
@Eelvex: Non. Fixé.
FUZxxl
La sortie du troisième testcase est incorrecte. La bonne réponse est -\frac{37745}{14592}x^4 - \frac{853249}{43776}x^3 + \frac{57809}{7296}x^2 + \frac{225205}{2736}x + \frac{23}{3}. Je soupçonne que l'entrée était censée être quelque chose de différent :)
Timwi

Réponses:

3

J + sh

Script J:

i=:0".(1!:1)3
i=:((-:#i),2)$i
c=:|.(%.(x:((i.#i)^~])"0({."1 i)))(+/ .*)(|:{:"1 i)
(":(-.0=c)#(c,.i.-#c))(1!:2)2

script sh:

echo -n 'f(x) = '
tr -d 'f()=' | tr /\\n- r' '_  | ./polyint.ijs | sed -e 's/^/+/;s/_/-/;s/\([0-9]*\)r\([0-9]*\)/\\frac{\1}{\2}/;s/ \([0-9]*$\)/x^\1/;s/\^1//;s/x^0//;s/+\(.*-.*\)/\1/'

Exécutez le script sh:

./pol-int.sh
f(1/2) = -1/2
f(-25) = -1/2
f(-54/12) = -1/2

f(x) = -\frac{1}{2}

.

./pol-int.sh
f(4/3) = 617/8
f(2) = 20/3
f(-8/3) = 6749/81
f(-5) = 7367/12
f(0) = 23/3

f(x) = -\frac{37745}{14592}x^4
       -\frac{853249}{43776}x^3
     +  \frac{57809}{7296}x^2
     + \frac{225205}{2736}x
     +  \frac{23}{3}
Eelvex
la source
Vous n'avez pas besoin de créer exactement le même formatage de code source. Dans la sortie LaTeX. Il devrait juste donner la même représentation graphique après avoir exécuté LaTeX. N'hésitez pas à enregistrer quelques caractères.
FUZxxl
Je ne peux pas lire J, mais d'après la courte longueur que je suppose, cela signifie que J a une fonction intégrée pour la forme échelonnée de la matrice?
Timwi
@ Timimi: Non, mais j'utilise la "matrice inverse" intégrée. J est cependant très concis: même si je devais implémenter une "matrice inversée", elle serait longue de quelques caractères.
Eelvex
3

Perl (569 caractères)

use Math'BigInt;sub r{($u,$v)=@_;$v?r($v,$u%$v):$u}sub c{new Math'BigInt$_[0]}$a=@c=<>;for(@c){m!(-?\d+)/?(\d*). = (-?\d+)/?(\d*)!;$j{$_,$i}=$1**c$_,$k{$_,$i|=0}=($2||1)**c$_ for 0..$a;$j{$a,$i}=c$3;$k{$a,$i++}=c$4||1}for$p(0..$a-1){for$y(0..$p-1,$p+1..$a-1){$n=$j{$p,$y}*$k{$p,$p};$o=$k{$p,$y}*$j{$p,$p};$j{$_,$y}=$j{$_,$y}*$k{$_,$p}*$o-$k{$_,$y}*$j{$_,$p}*$n,$k{$_,$y}*=$k{$_,$p}*$o for 0..$a}}print"f(x)=";for(1..$a){$s=r$t=$j{$a,$p=$a-$_}*$k{$p,$p},$w=$k{$a,$p}*$j{$p,$p};$u=abs$t,print$t>0?"$z":'-',($z='+',$w/=$s)-1?"\\frac{$u}{$w}":$u,$p>1?"x^$p":x x$p if$t/=$s}

Explication détaillée:

use Math'BigInt;

# Subroutine to calculate gcd of two numbers
sub r{($u,$v)=@_;$v?r($v,$u%$v):$u}

# Subroutine to create BigInts
sub c{new Math'BigInt$_[0]}

# Read input
# Throughout, $a is the number of equations.
$a=@c=<>;

# Initialises the $a+1 × $a matrix with all the values.
# $j{$x,$y} contains the numerator, $k{$x,$y} the denominator.
for(@c)
{
    m!(-?\d+)/?(\d*). = (-?\d+)/?(\d*)!;

    # Puzzle for the reader: why is $i|=0 in the second one,
    # not the first one? Answer at the bottom!
    $j{$_,$i}=$1**c$_,$k{$_,$i|=0}=($2||1)**c$_ for 0..$a;
    $j{$a,$i}=c$3;
    $k{$a,$i++}=c$4||1
}

# Generates the matrix echelon form.
# Basically, it works like this:
for$p(0..$a-1)
{
    # For each element along the diagonal {$p,$p}, set all the values above and
    # below it to 0 by adding a multiple of row $p to each of the other rows.
    for$y(0..$p-1,$p+1..$a-1)
    {
        # So we need to multiply the row $p by the value of {$p,$y}/{$p,$p}
        # (stored in $n/$o) and then subtract that from row $y.
        $n=$j{$p,$y}*$k{$p,$p};
        $o=$k{$p,$y}*$j{$p,$p};
            $j{$_,$y}=$j{$_,$y}*$k{$_,$p}*$o-$k{$_,$y}*$j{$_,$p}*$n,
            $k{$_,$y}*=$k{$_,$p}*$o
        for 0..$a
    }
}

# Outputs the result
print"f(x)=";
for(1..$a)
{
    # Note this sets $p = $a-$_. $p is the power of x.
    # We need to divide {$a,$p} by {$p,$p}. Store the result in $t/$w.
    # We also need to put the fraction in lowest terms, so calculate the gcd.
    $s=r$t=$j{$a,$p=$a-$_}*$k{$p,$p},$w=$k{$a,$p}*$j{$p,$p};

    # Output this term only if the numerator ($t) is non-zero.
    # Output a plus sign only if this isn’t the first term.
    # Output a fraction only if the denomator ($w) isn’t 1.
        $u=abs$t,print$t>0?"$z":'-',
        ($z='+',$w/=$s)-1?"\\frac{$u}{$w}":$u,$p>1?"x^$p":x x$p
    if$t/=$s
}

# Answer to the puzzle buried in the code above:
# It’s because the second part is passed as a second argument to c,
# hence it is evaluated before the first part.

commentaires

  • Je suis sûr qu'il existe un module de manipulation de matrice qui fournit une fonction pour la forme échelon. Je ne l'ai pas spécifiquement utilisé (je n'en ai même pas cherché) parce que je suppose que le but de ce concours est de le faire vous-même. C'est aussi plus intéressant de cette façon. Bien sûr, on pourrait en dire autant de BigInt, mais je suppose que personne ne tentera ce défi ...

Modifications

  • (630 → 585) Réalisé que je peux faire la forme échelon en une boucle au lieu de deux. Ajoutez une explication sous forme de commentaires dans le code.

  • (585 → 583) Je viens de découvrir la syntaxe du package qui me permet d'utiliser à la 'place de ::.

  • (583 → 573) Un peu plus de microgolf

  • (573 → 569) Expression régulière plus courte pour analyser l'entrée

Timwi
la source
Je continue de recevoir des erreurs de compilation: ideone.com/LoB2T
FUZxxl
@FUZxxl: Merci de l'avoir signalé. Il manquait juste un espace. Fixé maintenant.
Timwi
3

TI-Basic (83/84): 109 caractères

Techniquement 109 caractères, TI-Basic compte dim (, pour (, ->, rref (, [A]) et répertorie comme "un caractère".

L'entrée est formatée en L1 et L2, en paires (x, y) [ex L1 = (1,2,3,4), L2 = (2,3,5,7)].

{1,1}->dim([A]
{dim(L1),dim(L2)+1}->dim([A]
For(A,1,dim(L1)
For(B,dim(L1)-1,0,-1
L1(A)^B->[A](A,dim(L1)-B
End
L2(A->[A](A,dim(L1)+1
End
rref([A]->[A]
{0}->L3
For(A,1,dim(L1)
[A](A,dim(L1)+1->L3(A
End
Disp L3
beary605
la source
1
Cela n'utilise pas de rationnels ou de formulaire LaTeX.
lirtosiast
1

Méthode Lagrange, Python, 199 octets

Un peu tard, mais ...

def lagrange(dp):
l = lambda i: lambda x: (prod([(x - dp[j][0]) / (dp[i][0] - dp[j][0]) for j in range(len(dp)) if i != j]))
return lambda x: sum([l(i)(x) * dp[i][1] for i in range(len(dp))])
Fred Frey
la source
1
Vous n'avez probablement pas besoin de tout cet espace autour des opérateurs, n'est-ce pas?
0
l=lambda D,i:lambda x:prod((x-Dj[0])/(D[i][0]-Dj[0])for j,Dj in enumerate(D)if i!=j)
L=lambda D:lambda x:sum(l(D,i)(x)*Di[1]for i,Di in enumerate(D))

Juste une version abrégée du code Fred Freys. Notez que l'on pourrait probablement ignorer le passage de D à l, car il peut simplement le retirer de la portée externe. Comme vous pouvez probablement faire de même avec i ici, nous pourrions même raser un lambda. Je vais le tester un jour.

Teck-freak
la source