Imposta l'aritmetica teorica
Premessa
Ci sono già state un paio di sfide che implicano la moltiplicazione senza l'operatore della moltiplicazione ( qui e qui ) e questa sfida è sulla stessa linea (la maggior parte simile al secondo collegamento).
Questa sfida, a differenza di quelle precedenti, utilizzerà una definizione teorica stabilita dei numeri naturali ( N ):
e
per esempio,
e così via.
La sfida
Il nostro obiettivo è utilizzare le operazioni impostate (vedi sotto), per aggiungere e moltiplicare i numeri naturali. A tale scopo, tutte le voci saranno nella stessa "lingua impostata" il cui interprete è in basso . Ciò fornirà coerenza e punteggi più facili.
Questo interprete consente di manipolare i numeri naturali come set. Il tuo compito sarà quello di scrivere due corpi di programma (vedi sotto), uno dei quali aggiunge numeri naturali, l'altro che li moltiplica.
Note preliminari sugli insiemi
Gli insiemi seguono la solita struttura matematica. Ecco alcuni punti importanti:
- I set non sono ordinati.
- Nessun set contiene se stesso
- Gli elementi sono in un set o no, questo è booleano. Pertanto gli elementi dell'insieme non possono avere molteplicità (ovvero un elemento non può essere in un insieme più volte).
Interprete e dettagli
Un "programma" per questa sfida è scritto in "set language" e si compone di due parti: un'intestazione e un corpo.
Intestazione
L'intestazione è molto semplice. Indica all'interprete quale programma stai risolvendo. L'intestazione è la riga iniziale del programma. Inizia con il carattere +
o *
, seguito da due numeri interi, delimitato da spazi. Per esempio:
+ 3 5
o
* 19 2
sono intestazioni valide. Il primo indica che stai cercando di risolvere 3+5
, nel senso che la tua risposta dovrebbe essere 8
. Il secondo è simile tranne che per la moltiplicazione.
Corpo
Il corpo è dove sono le tue effettive istruzioni per l'interprete. Questo è ciò che costituisce veramente il tuo programma di "addizione" o "moltiplicazione". La tua risposta sarà composta da due organi del programma, uno per ciascun compito. Quindi dovrai modificare le intestazioni per eseguire effettivamente i casi di test.
Sintassi e istruzioni
Le istruzioni consistono in un comando seguito da zero o più parametri. Ai fini delle seguenti dimostrazioni, qualsiasi carattere alfabetico è il nome di una variabile. Ricorda che tutte le variabili sono insiemi. label
è il nome di un'etichetta (le etichette sono parole seguite da punti e virgola (cioè main_loop:
), int
è un numero intero. Di seguito sono riportate le istruzioni valide:
jump label
saltare incondizionatamente all'etichetta. Un'etichetta è una 'parola' seguita da un punto e virgola: ad esempiomain_loop:
è un'etichetta.je A label
passa all'etichetta se A è vuotojne A label
passa all'etichetta se A non è vuotojic A B label
passa all'etichetta se A contiene Bjidc A B label
passa all'etichetta se A non contiene B
print A
stampa il vero valore di A, dove {} è l'insieme vuotoprinti variable
stampa la rappresentazione intera di A, se esiste, altrimenti genera errori.
;
Il punto e virgola indica che il resto della riga è un commento e verrà ignorato dall'interprete
Ulteriori informazioni
All'avvio del programma, ci sono tre variabili preesistenti. Sono set1
,set2
e ANSWER
. set1
accetta il valore del primo parametro di intestazione. set2
prende il valore del secondo. ANSWER
è inizialmente l'insieme vuoto. Al completamento del programma, l'interprete verifica se ANSWER
è la rappresentazione intera della risposta al problema aritmetico definito nell'intestazione. Se lo è, lo indica con un messaggio a stdout.
L'interprete visualizza anche il numero di operazioni utilizzate. Ogni istruzione è un'operazione. L'avvio di un'etichetta costa anche un'operazione (le etichette possono essere avviate una sola volta).
Puoi avere un massimo di 20 variabili (incluse le 3 variabili predefinite) e 20 etichette.
Codice interprete
NOTE IMPORTANTI SU QUESTO INTERPRETOLe cose sono molto lente quando si usano numeri grandi (> 30) in questo interprete. Descriverò le ragioni di ciò.
- La struttura degli insiemi è tale che aumentando di un numero naturale, raddoppi effettivamente la dimensione della struttura dell'insieme. Il n ° numero naturale ha 2 ^ n insieme vuoto all'interno di esso (con questo voglio dire che se si guarda n come un albero, ci sono n insieme vuoto. Nota solo insieme vuoto può essere foglie.) Ciò significa che si tratta di 30 è significativamente più costoso rispetto a 20 o 10 (stai guardando 2 ^ 10 vs 2 ^ 20 vs 2 ^ 30).
- I controlli di uguaglianza sono ricorsivi. Dato che i set sono presumibilmente non ordinati, questo sembrava il modo naturale di affrontarlo.
- Ci sono due perdite di memoria che non sono riuscito a capire come risolvere. Mi dispiace per C / C ++, scusa. Dato che abbiamo a che fare solo con piccoli numeri e la memoria allocata viene liberata alla fine del programma, questo non dovrebbe essere un grosso problema. (Prima che qualcuno dica qualcosa, sì, lo so
std::vector
; lo stavo facendo come un esercizio di apprendimento. Se sai come ripararlo, per favore fammi sapere e farò le modifiche, altrimenti, dal momento che funziona, lo lascerò come è.)
Inoltre, notare il percorso di inclusione set.h
nel interpreter.cpp
file. Senza ulteriori indugi, il codice sorgente (C ++):
Set.h.
using namespace std;
//MEMORY LEAK IN THE ADD_SELF METHOD
class set {
private:
long m_size;
set* m_elements;
bool m_initialized;
long m_value;
public:
set() {
m_size =0;
m_initialized = false;
m_value=0;
}
~set() {
if(m_initialized) {
//delete[] m_elements;
}
}
void init() {
if(!m_initialized) {
m_elements = new set[0];
m_initialized = true;
}
}
void uninit() {
if(m_initialized) {
//delete[] m_elements;
}
}
long size() {
return m_size;
}
set* elements() {
return m_elements;
}
bool is_empty() {
if(m_size ==0) {return true;}
else {return false;}
}
bool is_eq(set otherset) {
if( (*this).size() != otherset.size() ) {
return false;
}
else if ( (*this).size()==0 && otherset.size()==0 ) {
return true;
}
else {
for(int i=0;i<m_size;i++) {
bool matched = false;
for(int j=0;j<otherset.size();j++) {
matched = (*(m_elements+i)).is_eq( *(otherset.elements()+j) );
if( matched) {
break;
}
}
if(!matched) {
return false;
}
}
return true;
}
}
bool contains(set set1) {
for(int i=0;i<m_size;i++) {
if( (*(m_elements+i)).is_eq(set1) ) {
return true;
}
}
return false;
}
void add(set element) {
(*this).init();
bool alreadythere = false;
for(int i=0;i<m_size;i++) {
if( (*(m_elements+i)).is_eq(element) ) {
alreadythere=true;
}
}
if(!alreadythere) {
set *temp = new set[m_size+1];
for(int i=0; i<m_size; i++) {
*(temp+i)= *(m_elements+i);
}
*(temp+m_size)=element;
m_size++;
delete[] m_elements;
m_elements = new set[m_size];
for(int i=0;i<m_size;i++) {
*(m_elements+i) = *(temp+i);
}
delete[] temp;
}
}
void add_self() {
set temp_set;
for(int i=0;i<m_size;i++) {
temp_set.add( *(m_elements+i) );
}
(*this).add(temp_set);
temp_set.uninit();
}
void remove(set set1) {
(*this).init();
for(int i=0;i<m_size;i++) {
if( (*(m_elements+i)).is_eq(set1) ) {
set* temp = new set[m_size-1];
for(int j=0;j<m_size;j++) {
if(j<i) {
*(temp+j)=*(m_elements+j);
}
else if(j>i) {
*(temp+j-1)=*(m_elements+j);
}
}
delete[] m_elements;
m_size--;
m_elements = new set[m_size];
for(int j=0;j<m_size;j++) {
*(m_elements+j)= *(temp+j);
}
delete[] temp;
break;
}
}
}
void join(set set1) {
for(int i=0;i<set1.size();i++) {
(*this).add( *(set1.elements()+i) );
}
}
void diff(set set1) {
for(int i=0;i<set1.size();i++) {
(*this).remove( *(set1.elements()+i) );
}
}
void intersect(set set1) {
for(int i=0;i<m_size;i++) {
bool keep = false;
for(int j=0;j<set1.size();j++) {
if( (*(m_elements+i)).is_eq( *(set1.elements()+j) ) ) {
keep = true;
break;
}
}
if(!keep) {
(*this).remove( *(m_elements+i) );
}
}
}
void natural(long number) {
//////////////////////////
//MEMORY LEAK?
//delete[] m_elements;
/////////////////////////
m_size = 0;
m_elements = new set[m_size];
for(long i=1;i<=number;i++) {
(*this).add_self();
}
m_value = number;
}
void disp() {
if( m_size==0) {cout<<"{}";}
else {
cout<<"{";
for(int i=0; i<m_size; i++) {
(*(m_elements+i)).disp();
if(i<m_size-1) {cout<<", ";}
//else{cout<<" ";}
}
cout<<"}";
}
}
long value() {
return m_value;
}
};
const set EMPTY_SET;
interpreter.cpp
#include<fstream>
#include<iostream>
#include<string>
#include<assert.h>
#include<cmath>
#include "headers/set.h"
using namespace std;
string labels[20];
int jump_points[20];
int label_index=0;
const int max_var = 20;
set* set_ptrs[max_var];
string set_names[max_var];
long OPERATIONS = 0;
void assign_var(string name, set other_set) {
static int index = 0;
bool exists = false;
int i = 0;
while(i<index) {
if(name==set_names[i]) {
exists = true;
break;
}
i++;
}
if(exists && index<max_var) {
*(set_ptrs[i]) = other_set;
}
else if(!exists && index<max_var) {
set_ptrs[index] = new set;
*(set_ptrs[index]) = other_set;
set_names[index] = name;
index++;
}
}
int getJumpPoint(string str) {
for(int i=0;i<label_index;i++) {
//cout<<labels[i]<<"\n";
if(labels[i]==str) {
//cout<<jump_points[i];
return jump_points[i];
}
}
cerr<<"Invalid Label Name: '"<<str<<"'\n";
//assert(0);
return -1;
}
long strToLong(string str) {
long j=str.size()-1;
long value = 0;
for(long i=0;i<str.size();i++) {
long x = str[i]-48;
assert(x>=0 && x<=9); // Crash if there was a non digit character
value+=x*floor( pow(10,j) );
j--;
}
return value;
}
long getValue(string str) {
for(int i=0;i<max_var;i++) {
if(set_names[i]==str) {
set set1;
set1.natural( (*(set_ptrs[i])).size() );
if( set1.is_eq( *(set_ptrs[i]) ) ) {
return (*(set_ptrs[i])).size();
}
else {
cerr<<"That is not a valid integer construction";
return 0;
}
}
}
return strToLong(str);
}
int main(int argc, char** argv){
if(argc<2){std::cerr<<"No input file given"; return 1;}
ifstream inf(argv[1]);
if(!inf){std::cerr<<"File open failed";return 1;}
assign_var("ANSWER", EMPTY_SET);
int answer;
string str;
inf>>str;
if(str=="*") {
inf>>str;
long a = strToLong(str);
inf>>str;
long b = strToLong(str);
answer = a*b;
set set1; set set2;
set1.natural(a); set2.natural(b);
assign_var("set1", set1);
assign_var("set2",set2);
//cout<<answer;
}
else if(str=="+") {
inf>>str;
long a = strToLong(str);
inf>>str;
long b = strToLong(str);
answer = a+b;
set set1; set set2;
set1.natural(a); set2.natural(b);
assign_var("set1", set1);
assign_var("set2",set2);
//cout<<answer;
}
else{
cerr<<"file must start with '+' or '*'";
return 1;
}
// parse for labels
while(inf) {
if(inf) {
inf>>str;
if(str[str.size()-1]==':') {
str.erase(str.size()-1);
labels[label_index] = str;
jump_points[label_index] = inf.tellg();
//cout<<str<<": "<<jump_points[label_index]<<"\n";
label_index++;
OPERATIONS++;
}
}
}
inf.clear();
inf.seekg(0,ios::beg);
// parse for everything else
while(inf) {
if(inf) {
inf>>str;
if(str==";") {
getline(inf, str,'\n');
}
// jump label
if(str=="jump") {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
// je set label
if(str=="je") {
inf>>str;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str) {
if( (*(set_ptrs[i])).is_eq(EMPTY_SET) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
break;
}
}
}
// jne set label
if(str=="jne") {
inf>>str;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str) {
if(! (*(set_ptrs[i])).is_eq(EMPTY_SET) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
break;
}
}
}
// jic set1 set2 label
// jump if set1 contains set2
if(str=="jic") {
inf>>str;
string str2;
inf>>str2;
set set1;
set set2;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str ) {
set1 = *(set_ptrs[i]);
}
if(set_names[i]==str2) {
set2 = *(set_ptrs[i]);
}
}
if( set1.contains(set2) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
else {inf>>str;}
}
// jidc set1 set2 label
// jump if set1 doesn't contain set2
if(str=="jidc") {
inf>>str;
string str2;
inf>>str2;
set set1;
set set2;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str ) {
set1 = *(set_ptrs[i]);
}
if(set_names[i]==str2) {
set2 = *(set_ptrs[i]);
}
}
if( !set1.contains(set2) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
else {inf>>str;}
}
// assign variable set/int
if(str=="assign") {
inf>>str;
string str2;
inf>>str2;
set set1;
set1.natural( getValue(str2) );
assign_var(str,set1);
OPERATIONS++;
}
// union set1 set2 set3
// set1 = set2 u set3
if(str=="union") {
inf>>str;
int i=0;
while(i<max_var) {
if( set_names[i] == str ) {
break;
}
i++;
}
set set1;
set set2;
string str1;
inf>>str1;
string str2;
inf>>str2;
for(int j=0;j<max_var;j++) {
if( str1 == set_names[j] ) {
set1= *(set_ptrs[j]);
}
if( str2 == set_names[j] ) {
set2= *(set_ptrs[j]);
}
}
set1.join(set2);
if(i==max_var) {
assign_var(str,set1);
}
else {
set_names[i]= str;
set_ptrs[i] = new set;
*(set_ptrs[i]) = set1;
}
OPERATIONS++;
}
// intersect set1 set2 set3
// set1 = set2^set3
if(str == "intersect") {
inf>>str;
int i=0;
while(i<max_var) {
if( set_names[i] == str ) {
break;
}
i++;
}
set set1;
set set2;
string str1;
inf>>str1;
string str2;
inf>>str2;
for(int j=0;j<max_var;j++) {
if( str1 == set_names[j] ) {
set1= *(set_ptrs[j]);
}
if( str2 == set_names[j] ) {
set2= *(set_ptrs[j]);
}
}
set1.intersect(set2);
if(i==max_var) {
assign_var(str,set1);
}
else {
set_names[i]= str;
set_ptrs[i] = new set;
*(set_ptrs[i]) = set1;
}
OPERATIONS++;
}
// difference set1 set2 set3
// set1 = set2\set3
if(str == "difference") {
inf>>str;
int i=0;
while(i<max_var) {
if( set_names[i] == str ) {
break;
}
i++;
}
set set1;
set set2;
string str1;
inf>>str1;
string str2;
inf>>str2;
for(int j=0;j<max_var;j++) {
if( str1 == set_names[j] ) {
set1= *(set_ptrs[j]);
}
if( str2 == set_names[j] ) {
set2= *(set_ptrs[j]);
}
}
set1.diff(set2);
if(i==max_var) {
assign_var(str,set1);
}
else {
set_names[i]= str;
set_ptrs[i] = new set;
*(set_ptrs[i]) = set1;
}
OPERATIONS++;
}
// add set1 set2
// put set2 in set 1
if(str=="add") {
inf>>str;
int i = 0; int j =0;
while(i<max_var) {
if(set_names[i]==str) {
break;
}
i++;
}
inf>>str;
while(j<max_var) {
if(set_names[j]==str) {
break;
}
j++;
}
set set2 = *(set_ptrs[j]);
if( ! (*(set_ptrs[i])).is_eq(set2) ){
(*(set_ptrs[i])).add(set2);
}
else {
(*(set_ptrs[i])).add_self();
}
OPERATIONS++;
}
// remove set1 set2
// remove set2 from set1
if(str=="remove") {
inf>>str;
int i = 0; int j =0;
while(i<max_var) {
if(set_names[i]==str) {
break;
}
i++;
}
inf>>str;
while(j<max_var) {
if(set_names[j]==str) {
break;
}
j++;
}
set set2 = *(set_ptrs[j]);
(*(set_ptrs[i])).remove(set2);
OPERATIONS++;
}
// print set
// prints true representation of set
if(str=="print") {
inf>>str;
for(int i=0;i<max_var;i++) {
if(set_names[i]==str) {
(*(set_ptrs[i])).disp();
}
}
cout<<"\n";
}
// printi set
// prints integer representation of set, if exists.
if(str=="printi") {
inf>>str;
cout<<getValue(str);
cout<<"\n";
}
}
}
cout<<"You used "<<OPERATIONS<<" operations\n";
set testset;
testset.natural(answer);
switch( testset.is_eq( *(set_ptrs[0]) ) ) {
case 1:
cout<<"Your answer is correct, the set 'ANSWER' is equivalent "<<answer<<".\n";
break;
case 0:
cout<<"Your answer is incorrect\n";
}
// cout<<"\n";
return 0;
}
Condizioni vincenti
Siete in due a scrivere due programmi CORPO , uno dei quali moltiplica i numeri nelle intestazioni, l'altro aggiunge i numeri nelle intestazioni.
Questa è una sfida con il codice più veloce . Ciò che è più veloce sarà determinato dal numero di operazioni utilizzate per risolvere due casi di test per ciascun programma. I casi di test sono le seguenti righe di intestazioni:
Per aggiunta:
+ 15 12
e
+ 12 15
e per moltiplicazione
* 4 5
e
* 5 4
Un punteggio per ciascun caso è il numero di operazioni utilizzate (l'interprete indicherà questo numero al completamento del programma). Il punteggio totale è la somma dei punteggi per ciascun caso di test.
Vedi la mia voce di esempio per un esempio di voce valida.
Una presentazione vincente soddisfa quanto segue:
- contiene due corpi di programma, uno che si moltiplica e uno che aggiunge
- ha il punteggio totale più basso (somma dei punteggi nei casi di test)
- Dato tempo e memoria sufficienti, funziona per qualsiasi numero intero che potrebbe essere gestito dall'interprete (~ 2 ^ 31)
- Non visualizza errori durante l'esecuzione
- Non utilizza i comandi di debug
- Non sfrutta i difetti nell'interprete. Ciò significa che il tuo programma effettivo dovrebbe essere valido come pseudo-codice e come programma interpretabile in "lingua impostata".
- Non sfrutta le scappatoie standard (ciò significa che non esistono casi di test hardcoding).
Si prega di consultare il mio esempio per l'implementazione di riferimento e l'uso di esempio della lingua.
$$...$$
funziona su Meta, ma non su Main. Ho usato CodeCogs per generare le immagini.