Mathematische Substitution

13

Manchmal ist es nützlich, ein mathematisches Problem mit mehreren Eingaben auszuführen. Ziel dieser Herausforderung ist es, ein Programm zu entwickeln, das diese Aufgabe erleichtert.

Zahlenerzeugende Ausdrücke

Sie müssen 3 Ausdruckstypen unterstützen:

  • Single Number Generator: Sehr einfach, nur eine wörtliche Zahl
  • Generator mit mehreren Nummern: Etwas komplizierter. Sie sind von eckigen Klammern ( []) umgeben. Zahlen werden ,im Ausdruck durch Kommas ( ) getrennt. Beispiel [-1,2,3.26].
  • Bereichsgenerator: Dieser ist von geschweiften Klammern ( {}) umgeben. Es werden 3 durch Komma getrennte Zahlen angezeigt. Das Format dieses Ausdrucks ist {start,stop,step}. startund stopsind inklusive.

Regeln für die Bewertung

  • Sie müssen die Reihenfolge der Operationen unterstützen. ( https://en.wikipedia.org/wiki/Order_of_operations#Definition )
  • Klammern müssen nicht unterstützt werden.
  • Der Ausdruck darf beliebig viele Leerzeichen enthalten.
  • Sie müssen Gleitkommazahlen unterstützen (unabhängig von der Genauigkeit, mit der Ihre Sprache standardmäßig arbeitet).
  • Division durch 0Ergebnisse in NaN(keine Zahl).

Ihr Programm muss Multiplikation ( *), Division ( /), Addition ( +) und Subtraktion ( -) unterstützen.

Ausgabe

Jede Ausgabezeile ist eine der Kombinationen der Generatoren. Das Format ist der Ausdruck (mit den reellen Zahlen), gefolgt von einem Gleichheitszeichen ( =) und dem Ergebnis der Auswertung. Alle Kombinationen der Generatoren müssen in der Ausgabe dargestellt werden.

Beispiele

( >>>bezeichnet die Eingabe)

>>>3 * [3,2]
3 * 3 = 9
3 * 2 = 6

>>>{1,2,3}
1 = 1 <-- this is because 1 + 3 > the end

>>>{0,2,1} + {0,1,1}
0 + 0 = 0
1 + 0 = 1
2 + 0 = 2
0 + 1 = 1
1 + 1 = 2
2 + 1 = 3

>>>6/[2,3]
6/2 = 3
6/3 = 2

>>>{1.5,2.5,0.5}
1.5 = 1.5
2 = 2
2.5 = 2.5

>>>3-{6,5,-1}
3-6 = -3
3-5 = -2

>>>5/{-1,1,1}
5/-1 = -5
5/0 = NaN
5/1 = 5

>>>4.4 / [1,2.2] + {0,2,1}
4.4 / 1 + 0 = 4.4
4.4 / 1 + 1 = 5.4
4.4 / 1 + 2 = 6.4
4.4 / 2.2 + 0 = 2
4.4 / 2.2 + 1 = 3
4.4 / 2.2 + 2 = 4

>>> [1,2] / 0 + 5
1 / 0 + 5 = NaN
2 / 0 + 5 = NaN

Das Programm muss kurz sein, damit ich es mir merken und überall verwenden kann.

Vielen Dank an @PeterTaylor und @geokavel, die mir bei diesem Beitrag im Sandkasten geholfen haben

J Atkin
quelle
Sie müssen Gleitkommazahlen unterstützen (unabhängig von der Genauigkeit, mit der Ihre Sprache standardmäßig arbeitet). Was ist, wenn meine Sprache nur Ganzzahlarithmetik unterstützt? Kann ich behaupten, dass ich FP mit einer Genauigkeit von null Dezimalstellen habe?
Digitales Trauma
Kann der Eingang Bereiche und Mehrfachnummern mischen?
Maltysen
@DigitalTrauma Ich habe nicht an diese Sprachen gedacht .... Ich würde nein sagen.
J Atkin
Auch dann , wenn x/0Ergebnis in sofortige Auswertung NaN, oder muss ich NaN als Wert behandeln?
Maltysen
@Maltysen Ja, sollte ich ein Beispiel hinzufügen?
J Atkin

Antworten:

4

JavaScript (ES6), 213 211 Byte

f=x=>(a=0,x=x.replace(/\[.+?]|{.+?}/,r=>([i,l,n]=a=r.slice(1,-1).split`,`,r[0]>"]"&&eval(`for(a=[];n>0?i<=+l:i>=+l;i-=-n)a.push(i)`),"x")),a?a.map(n=>f(x.replace("x",n))).join``:x+` = ${r=eval(x),r<1/0?r:NaN}
`)

Erläuterung

Eine rekursive Funktion, die den Ausdruck ausführt, wenn sie keine Generatoren für mehrere Zahlen oder Bereiche enthält oder wenn sie einen dieser Generatoren enthält, ruft sich selbst auf, wobei der Generator durch jede von ihr erzeugte Zahl ersetzt wird.

Das Teilen durch 0in JavaScript erzeugt Infinity, Infinitykann also einfach durch ersetzt werden NaN.

Mit dieser Methode werden die Multi-Generatoren von vorne nach hinten und nicht wie in den Testfällen von vorne nach hinten analysiert. Dies bedeutet nur, dass die Reihenfolge der Ausgabeausdrücke manchmal anders ist.

f=x=>(
  a=0,                                           // initialise a to false
  x=x.replace(/\[.+?]|{.+?}/,r=>(                // find the first multi-generator
    [i,l,n]=                                     // i = start, l = stop, n = step
      a=r.slice(1,-1).split`,`,                  // a = each number of generator
    r[0]>"]"&&                                   // if a range generator was found
      eval(`                                     // use eval to enable for loop here
        for(a=[];n>0?i<=+l:i>=+l;i-=-n)a.push(i) // add each number of the range to a
      `),
    "x"                                          // replace the generator with "x"
  )),
  a?                                             // if a multi-generator was found
    a.map(n=>                                    // for each number n in a
      f(x.replace("x",n))                        // call itself with n inserted
    )
    .join``                                      // combine the output of each result
  :x+` = ${r=eval(x),                            // evaluate the expression
    r<1/0?r:NaN}
`                                                // replace Infinity with NaN
)

Prüfung

Test verwendet aus Gründen der Browserkompatibilität keine destrukturierenden Zuweisungen.

f=x=>(a=0,x=x.replace(/\[.+?]|{.+?}/,r=>(a=r.slice(1,-1).split`,`,r[0]>"]"&&eval(`i=a[0],l=a[1],n=a[2];for(a=[];n>0?i<=+l:i>=+l;i-=-n)a.push(i)`),"x")),a?a.map(n=>f(x.replace("x",n))).join``:x+` = ${r=eval(x),r<1/0?r:NaN}
`)
<input type="text" id="input" value="4.4 / [1,2.2] + {0,2,1}" />
<button onclick="result.textContent=f(input.value)">Go</button>
<pre id="result"></pre>

user81655
quelle
Dies ist eigentlich sehr nah an meiner geplanten Antwort.
J Atkin
4

Haskell, 474 362 Bytes

Die Funktion f nimmt einen String als Eingabe und druckt die Ergebnisse

g '+'=(+);g '-'=(-);g '*'=(*);g '/'=(\a b->a*b/b/b)
p[]=[]
p(o:x:y)=[(flip(g o)$n,' ':o:' ':show n)|n<-v]:p r where
    [f,e,s]=z;(z,h)=reads('[':y)!!0;(w,m)=reads(x:y)!!0;(v,r)|x=='['=(z,h)|x=='{'=([f,f+s..e],h)|True=([w],m)
h '}'=']';h x=x
d(a,b)=putStrLn.drop 3$foldl(++)""b++" = "++show(foldl(flip($))0a)
f t=mapM_(d.unzip)$sequence$p(filter(/=' ')$'+':map h t)

Tests:

main=do
    f "4.4 / [1,2.2] + {0,2,1}"
    putStrLn""
    f "[1,2] / 0 + 5"
    putStrLn""
    f "{0,2,1} + {0,1,1}"

Ausgabe:

4.4 / 1.0 + 0.0 = 4.4
4.4 / 1.0 + 1.0 = 5.4
4.4 / 1.0 + 2.0 = 6.4
4.4 / 2.2 + 0.0 = 2.0
4.4 / 2.2 + 1.0 = 3.0
4.4 / 2.2 + 2.0 = 4.0

1.0 / 0.0 + 5.0 = NaN
2.0 / 0.0 + 5.0 = NaN

0.0 + 0.0 = 0.0
0.0 + 1.0 = 1.0
1.0 + 0.0 = 1.0
1.0 + 1.0 = 2.0
2.0 + 0.0 = 2.0
2.0 + 1.0 = 3.0
Damien
quelle
2

Python 3, 387 Bytes

def a(q,d=-1,f='',g=float,h=print):
 if any((c in q)for c in'[]{}'):
  for i,b in enumerate(q):
   if d!=-1:
    if b in'}]':
     e=f.split(",")
     if b=='}':
      r=g(e[0]);s=[]
      while r<=g(e[1]):s.append(str(r));r+=g(e[2])
      e[:]=s[:]
     [a(q[:d]+n+q[i+1:])for n in e];return
    f+=b
   if b in'[{':d=i
 else:
  h(q+" = ",end='')
  try:h(str(eval(q)))
  except:h("NaN")

Sie können es mit dem folgenden Code testen:

tests=['3 * [3,2]', '{1,2,3}', '{0,2,1} + {0,1,1}',
       '6/[2,3]', '{1.5,2.5,0.5}', '3-{6,5,-1}',
       '5/{-1,1,1}', '4.4 / [1,2.2] + {0,2,1}',
       '[1,2] / 0 + 5']

for n in tests:
    print(n)
    a(n)
    print()

Hier ist der Code ungolfed:

def eval_statement(query):
    left_bracket_index = -1
    inside_bracket_content = ''
    if any((bracket in query) for bracket in '[]{}'):
        for i, character in enumerate(query):
            if left_bracket_index != -1:
                if character in '}]':
                    params = inside_bracket_content.split(",")
                    if character == '}':
                        value = float(params[0])
                        values = []
                        while value <= float(params[1]):
                            values.append(str(value))
                            value += float(params[2])
                        params[:] = values[:]
                    for param in params:
                        new_query = query[:left_bracket_index] + param + query[i + 1:]
                        eval_statement(new_query)
                    return
                inside_bracket_content += character
            if character in '[{':
                left_bracket_index = i
    else:
        print(query + " = ", end='')
        try:
            print(str(eval(query)))
        except:
            print("NaN")

Es funktioniert, indem der erste Satz von Klammern eines beliebigen Typs gefunden und dann alle darin enthaltenen Werte durchlaufen werden, indem die Klammern und ihr Inhalt durch den Wert ersetzt werden und die Methode rekursiv ausgeführt wird. Wird verwendet, evalwenn sich keine Klammern in der Zeile befinden. Es wird zurückgegeben, NaNwenn eine Ausnahme ausgeführt wird eval.

Cameron Aavik
quelle
(etwas spät) Willkommen bei Programming Puzzles & Code Golf!
J Atkin
Warum brauchen Sie e[:]=s[:]? Würde das nicht e[:]=sauch so sein?
Cyoce
1

Java, 874 Bytes

void E(String s)throws Exception{int i=0;String t;List<String[]>z=new ArrayList<>();List<String>x=new ArrayList<>(),y=new ArrayList<>();for(String k:s.split(" "))t+=" "+(k.matches("[0-9]+")?"["+k+"]":k);for(String k:t.split(" "))s+=" "+(k.matches("\\{[^\\}]+\\}")?"["+R(k)+"]":k);for(String k:s.split(" "))t+=" "+(k.matches("\\[[^\\]]+\\]")?"$"+(i+=z.add(k.replaceAll("[\\[\\]]","").split(","))):k);x.add(t.substring(1));while (i-->0){y.clear();for(String e:x)for(String l:z.get(i))y.add(e.replace("$"+i,l));x.clear();x.addAll(y);}for(String e:x)System.out.println(e+"="+new javax.script.ScriptEngineManager().getEngineByName("JavaScript").eval(e).replace("Infinity","NaN"));}
String R(String t){String y="",[]s=t.replaceAll("[\\{\\}]","").split(",");int i=I(s[0]);y+="["+i;while ((i+=I(s[2]))<=I(s[1]))y+=","+i;y+="]";return y;}
int I(String t){return Integer.parseInt(t);}

Ausführlicher Versuch hier

import java.util.*;
import java.lang.*;
import java.io.*;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;

class Ideone
{
    // single : x -> [x]
    public static String expandSingle (String input)
    {
        String out = "";
        for (String str : input.split(" "))
        {
            out += " ";
            if(str.matches("[0-9]+"))
            {
                out += "["+str+"]";
            }
            else
            {
                out += str;
            }
        }
        return out.substring(1);
    }

    // range : {start,end,step} -> [x,..,y]
    public static String expandRange (String input)
    {
        String out = "";
        int a,b,c;
        int i=0;
        for (String str : input.split(" "))
        {
            out += " ";
            if(str.matches("\\{[0-9]+,[0-9]+,[0-9]+\\}"))
            {
                str = str.replaceAll("[\\{\\}]","");
                a = Integer.parseInt(str.split(",")[0]);
                b = Integer.parseInt(str.split(",")[1]);
                c = Integer.parseInt(str.split(",")[2]);

                out += "["+a;
                while ((a+=c) <= b) out += ","+a;
                out += "]";
            }
            else
            {
                out += str;
            }
        }
        return out.substring(1);
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        String input = "3 * [3,2] + {0,2,1}";
        System.out.println(" input = "+input);
        input = expandSingle(input);
        input = expandRange(input);
        System.out.println(" expand = "+input);
        evaluate(input);
    }

    public static void evaluate (String input) throws java.lang.Exception
    {
        int i = 0;
        String t = "";
        ArrayList<String[]> set = new ArrayList<String[]>();
        ArrayList<String> in = new ArrayList<String>();
        ArrayList<String> out = new ArrayList<String>();

        // map sets
        for (String str : input.split(" "))
        {
            t += " ";
            if(str.matches("\\[.+\\]"))
            {
                str = str.replaceAll("[\\[\\]]","");
                set.add(str.split(","));
                t+= "$"+i;
                i++;
            }
            else t+=str;
        }
        in.add(t.substring(1));

        // generate expressions
        while (i-->0)
        {
            out.clear();
            for (String exp : in)
            {
                for (String sub : set.get(i))
                {
                    out.add(exp.replace("$"+i,sub));
                }
            }
            in.clear();
            in.addAll(out);
        }

        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine engine = mgr.getEngineByName("JavaScript");

        // print expressions
        for (String exp : in)
        {
            System.out.println(" "+exp+" = "+engine.eval(exp).replace("Infinity","NaN"));
        }
    }
}
Khaled.K
quelle
1

Dyalog APL , 164 Bytes

Diese Antwort entspricht nicht den aktualisierten Anforderungen und ist daher nicht konkurrierend:

{n←⊂'NaN'
R←{+\b,s/⍨⌊((2⊃⍵)-b←⊃⍵)÷s←⊃⌽⍵}
D←{0::n⋄⍺×÷⍵}
↑(∊¨(,⍎'[-+×D]'⎕R','⊢e),¨¨⊂('[-+×÷]'⎕S'\0'⊢⍵),⊂'='),¨,⍎e←'{' '}' '\[' ']' '÷' '[-+×]'⎕R'(R ' ')' '(' ')' '∘.D ' '∘.{0::n⋄⍺\0⍵}'⊢⍵}

Es verwendet reguläre Ausdrücke, um den angegebenen Ausdruck in die entsprechende APL zu ändern (und alle Operatoren werden zur Implementierung geändert NaN ) und die Operatoren zu extrahieren. Es ersetzt alle Operatoren durch Verkettung und führt den Ausdruck aus, um die endgültigen Eingabenummern zu erhalten. Anschließend wird alles zusammengefügt, um die endgültige Ausgabe zu erhalten.

Erhält die Reihenfolge der Bewertung von APL (strikt von rechts nach links).

Behandelt Klammern richtig.

Testfälle (mit zusätzlichen Klammern, um eine mathematische Ausführungsreihenfolge zu erzwingen):

      f '3 × [3,2]'
3 × 3 = 9
3 × 2 = 6
      f '{1,2,3}'
1 = 1
      f '{0,2,1} + {0,1,1}'
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 2
2 + 0 = 2
2 + 1 = 3
      f '6÷[2,3]'
6 ÷ 2 = 3
6 ÷ 3 = 2
      f '{1.5,2.5,0.5}'
1.5 = 1.5
2   = 2  
2.5 = 2.5
      f '3-{6,5,¯1}'
3 - 6 = ¯3
3 - 5 = ¯2
      f '5÷{¯1,1,1}'
5 ÷ ¯1 =  ¯5 
5 ÷  0 = NaN 
5 ÷  1 =   5 
      f '(4.4 ÷ [1,2.2]) + {0,2,1}'
4.4 ÷ 1   + 0 = 4.4
4.4 ÷ 1   + 1 = 5.4
4.4 ÷ 1   + 2 = 6.4
4.4 ÷ 2.2 + 0 = 2  
4.4 ÷ 2.2 + 1 = 3  
4.4 ÷ 2.2 + 2 = 4  
      f '([1,2] ÷ 0) + 5'
1 ÷ 0 + 5 = NaN 
2 ÷ 0 + 5 = NaN 
Adam
quelle
Besteht es die (unveränderten) Testfälle? Wenn ja, dann ist es in Ordnung.
J Atkin
@JAtkin Jetzt schauen.
Adám
Nein, soweit ich weiß, wird die Reihenfolge der Operationen immer noch nicht unterstützt.
J Atkin
@JAtkin "Sie müssen die Reihenfolge der Operationen unterstützen." Sie haben nie angegeben, welche Reihenfolge. Dies tut unterstützen die Reihenfolge der verwendeten Sprache. Jede Sprache (einschließlich Mathematik der Oberstufe) hat einen willkürlichen (aber leider manchmal sogar mehrdeutigen) Vorrangregelsatz. Der Regelsatz von APL ist eindeutig.
Adám
1
Der Standard für Mathematik ist, was ich angedeutet habe: en.wikipedia.org/wiki/Order_of_operations#Definition . Ich werde das jetzt zum Beitrag hinzufügen
J Atkin