Re: Scripting Contest

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 29.06.2022 15:25:41


Abgespalten von viewtopic.php?p=1304905#p1304905




Bei mir sieht der Aufruf und die Ausgabe derzeit so aus:

Code: Alles auswählen

:-/ ./str2double-manual
aaa23434.45656456 7787,56456.546.456.456 f.123xx
number is: 23434.456565
number is: 7787.000000
number is: 56456.546000
number is: 456.456000
^D
Die erste Zeile nach dem Programmaufruf ist meine Eingabe und die darauffolgenden vier Zeilen die Programmausgabe. (An den Nachkommastellen und der Rundung beim ersten Wert laesst sich erahnen, dass es tatsaechlich doubles sind, die ich hier ausgebe.)

Die Darstellung ``.123'' wird derzeit nicht erkannt. Das koennte ich noch aendern wenn gewuenscht.

Der Fall mit mehreren Punkten zwischen Zahlen wird IMO korrekt erkannt, aber vielleicht hast du da auch andere Vorstellungen wie es sein sollte.


Nachtrag: Die Eingabe lese ich ausschliesslich mit `getchar()'. Die Ausgabe mache ich mit `printf("number is: %lf\n", ...)'.
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Scripting Contest: Zahl erkennen: Fragen zu C

Beitrag von inne » 29.06.2022 15:45:32

Wie die Angabe des Eingabewertes ist sollte schon einheitlich sein. Und über die Kommandozeile, können wir das Skript von heisenberg(?) nutzen, was damals auch bei der Aufgabe Regenbogentabelle genommen wurde. Der Sieger ist dann die Lösung die schneller tut?

Eingaben wie .0123 oder 00123.056 sollten schon auch funktionieren, weil es IMO gültige Schreibweisen sind. Bei mir ergibt sich das aus der Logik und funktioniert.

In Perl habe ich aber nur meinen Rechenweg kontrolliert:

Code: Alles auswählen

 wc 2d.pl 
 22  63 420 2d.pl
Ich werde das nun in C schreiben, damit ein Vergleich unserer Lösungen besser funktioniert. Muss mich aber noch kurz einlesen in C, delimiter (denn in Perl habe ich split und reverse splip genommen) usw. was aber dann wohl wieder auf Lasten der Performace geht. Nun gut... das ist dann jedem sein Code :-)

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 29.06.2022 16:05:19

Der Input soll also ein Kommandozeilenargument sein und nicht von Stdin gelesen werden?

Soll genau ein Kommandozeilenargument genau eine Zahl ergeben oder muss das Programm den Eingabestring selber teilen? Falls zweiteres, wie ist dann ``12.34.56'' zu interpraetieren: 12.34 und 56 -- oder 12.34 und 0.56?

.123 und 00123.45 kann man Programm jetzt.
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 29.06.2022 16:29:08

inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 15:10:00

Code: Alles auswählen

sol 123.056
number is: 123.056
Lass uns bei diesem einen Aufruf bleiben (Wäre der möglich?) dann kann die Eingabe als gültig angenommen werden und muss nicht weiter geprüft werden.
Für C wäre die Eingabe also argv[1] und die Ausgabe printf("number is: %lf\n", ...)' scheint mir ok.

Mit diesem Prüfscript von heisenberg wollte ich dann Vergleichen:
viewtopic.php?p=1092042#p1092039
Ich muss nochmal reinschauen, aber ggf. muss jemand eine Wiederholung einbauen, um einen Unterschied zu erkennen ähnlich wie benchmark bei Perl? Aber soweit bin ich noch nicht. Bis morgen werde ich mit C wohl brauchen.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 29.06.2022 16:50:09

Alles klar. Wir sollten uns noch auf eine Anzahl von Nachkommastellen bei der Ausgabe festlegen. Ich habe jetzt mal 3 genommen, wie in deiner Beispielausgabe, also: `printf("number is: %.3lf\n", ...)'


Hier ist mal eine Reihe von Eingaben und Ausgaben:

Code: Alles auswählen

:-/ ./str2dbl 1                     
number is: 1.000

:-/ ./str2dbl 123456
number is: 123456.000

:-/ ./str2dbl 12345678901234
number is: 12345678901234.000

:-/ ./str2dbl 1.234         
number is: 1.234

:-/ ./str2dbl 1234.234
number is: 1234.234

:-/ ./str2dbl 0.99    
number is: 0.990

:-/ ./str2dbl 0.01
number is: 0.010

:-/ ./str2dbl 0.0     
number is: 0.000

:-/ ./str2dbl .5  
number is: 0.500

:-/ ./str2dbl 1.234567
number is: 1.235

:-/ ./str2dbl 123..45
number is: 123.000

:-/ ./str2dbl ..99
no number

:-/ ./str2dbl a5a 
no number
Ist das alles wie es sein soll?

(Ich habe kein Lua, kann das Pruefscript darum nicht nutzen.)
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 29.06.2022 18:16:11

Bin nun auch in C fertig:

Code: Alles auswählen

$ wc 2d.c
 30  91 695 2d.c
$ ./a.out 123.056
number is: 123.056
Aber ich nutze an einer (imo vertrebaren) Stelle atoi, anstatt das auch selbst zu basteln.

Deine Ausgaben sind soweit OK denke ich, bis auf:
123..45
..99
a5a

Fehlerhafte Eingaben wollte ich gern weglassen. Aber ich schau mal wie ich das abgefragt bekomme. Noch habe ich keine Fehlerbehandlung, aber dazu mache ich mir mal morgen Gedanken zu. Das ist in C für mich nicht so einfach. Erstmal wieder an C-Strings und die Rechnerei mit Speicheraddressen gewöhnen :-)

Kann Du mal ein wc auf deinen Code machen bitte!

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 29.06.2022 19:04:38

inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 18:16:11
Deine Ausgaben sind soweit OK denke ich, bis auf:
123..45
..99
a5a
Die Frage ist nur: Was soll das Programm in den Faellen machen? Ich kann einen Fehler ausgeben, wenn die Zahl nicht das gesamte Argument umfasst, oder ich kann von vorne her so viel matchen wie geht, oder ich kann ab der ersten Zahl so viel matchen wie geht. Das kannst du beliebig festlegen. Mir geht es nur darum, *dass* es festgelegt ist. Darum habe ich die Testdaten verarbeiten lassen.
inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 18:16:11
Fehlerhafte Eingaben wollte ich gern weglassen.
Auch das ist eine Moeglichkeit: Dass das Programm nur valide Werte bekommt. (Du kannst es dir frei aussuchen ... nur solltest du es uns wissen lassen. ;-)

inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 18:16:11
Kann Du mal ein wc auf deinen Code machen bitte!

Code: Alles auswählen

:-/ wc str2dbl.c   
      44     111     632 str2dbl.c
Ich mache die Zahlenrechnerei von Hand. An Funktionen nutze ich nur folgende:

Code: Alles auswählen

:-/ egrep -o '\<[a-z0-9_]+\(' str2dbl.c
main(
fprintf(
isdigit(
printf(
puts(
Die drei verschiedenen Ausgabefunktionen (fprintf(), printf() und puts()) koennte ich natuerlich auch alle mit nur fprintf() abbilden.

isdigit() koennte ich auch mit einem Zeichenvergleich loesen. Das waeren dann acht Zeichen mehr Dateiinhalt.

Formatiert habe ich den Code in meinem normalen Programmierstil.
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 29.06.2022 19:32:33

Meillo hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 19:04:38
inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 18:16:11
Deine Ausgaben sind soweit OK denke ich, bis auf:
123..45
..99
a5a
Die Frage ist nur: Was soll das Programm in den Faellen machen?
Alle drei Fälle sind doch ungültig, nicht nur die letzten beiden.
Meillo hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 19:04:38
Ich kann einen Fehler ausgeben
Genau! Immer wenn argv[1] ungültig ist, hört das Programm auf. Und alle drei Werte oben sind dies für mich.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 29.06.2022 20:40:55

inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 19:32:33
Meillo hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 19:04:38
inne hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 18:16:11
Deine Ausgaben sind soweit OK denke ich, bis auf:
123..45
..99
a5a
Die Frage ist nur: Was soll das Programm in den Faellen machen?
Alle drei Fälle sind doch ungültig, nicht nur die letzten beiden.
Meillo hat geschrieben: ↑ zum Beitrag ↑
29.06.2022 19:04:38
Ich kann einen Fehler ausgeben
Genau! Immer wenn argv[1] ungültig ist, hört das Programm auf. Und alle drei Werte oben sind dies für mich.
Alles klar. Ich hab's angepasst:

Code: Alles auswählen

:-/ ./str2dbl ..99
no number

:-/ ./str2dbl 123..45
no number

:-/ ./str2dbl ..99   
no number

:-/ ./str2dbl a5a 
no number
Dabei bin ich noch auf einen neuen Fall gestossen. Was ist mit:

Code: Alles auswählen

:-/ ./str2dbl 7.  
number is: 7.000
? Ist ``7.'' ebenfalls eine Nummer wie ``.2'' oder soll ``7.'' einen Fehler werfen?
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 29.06.2022 21:24:07

Ich bin kein Mathematiker und weiss nicht alles über die Schreibweise :mrgreen:
Aber anders als .7 macht 7. für mich keinen Sinn und ich würde es als Fehler behandeln.
Zuletzt geändert von inne am 01.07.2022 14:50:31, insgesamt 1-mal geändert.

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 30.06.2022 13:43:04

Das benutzen von atoi habe ich nun auch raus, denn mir viel wieder ein, dass die character bei 48 beginnen + abgebildeter Zahlwert 0 bis 9.

Code: Alles auswählen

egrep -o '\<[a-z0-9_]+\(' 2d.c
main(
strtok(
strtok(
strlen(
strlen(
printf(
Ich kann nur nicht sagen, wie sich das benutzen von strtok und strlen auswirkt (Stream vs. Matrix?). Im Grunde wäre es nur Rechnen mit den Positionen in argv[1], was ein zweidimensionales Array ist, wenn ich das richtig verstanden habe?

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 30.06.2022 18:28:36

inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 13:43:04
Das benutzen von atoi habe ich nun auch raus, denn mir viel wieder ein, dass die character bei 48 beginnen + abgebildeter Zahlwert 0 bis 9.
Bloss solltest du nicht die Magic Number 48 verwenden, sondern stattdessen schreiben. Vom Zahlzeichen zum Zahlwert kommt man in C mittels:

Code: Alles auswählen

char c;
int n;

if (isdigit(c)) {
	n = c - '0'
}
inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 13:43:04
Im Grunde wäre es nur Rechnen mit den Positionen in argv[1], was ein zweidimensionales Array ist, wenn ich das richtig verstanden habe?
`argv' ist ein Array von Char-Pointern, die auf Arrays von Char zeigen. Ein wirklich zweidimensionales Array ist das nicht (weil die Zeilen unterschiedlich lang sein koennen), aber man kann es in aehnlicher Form nutzen.

`argv[1]' ist ein Char-Array (d.h. ein null-terminierter C-String).

Du kannst mit einem Index auf beliebige Zeichen dieses Strings zugreifen, was du derzeit wohl machst. Alternativ kannst du mit einem Char-Pointer mittels Pointer-Arithmetik ueber den String wandern, was ein ueblicherer Stil erfahrener C-Programmierer ist. Letzteres ist fuer Nicht-C-Programmierer aber meist unintuitiver.
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 30.06.2022 19:14:48

Meillo hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 18:28:36
Bloss solltest du nicht die Magic Number 48 verwenden, sondern stattdessen schreiben.
Danke für den Hinweis. Was ist der Unterschied zu 48, also der Hintergrund es so zu schreiben, die Portabilitär?
inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 13:43:04
Ein wirklich zweidimensionales Array ist das nicht (weil die Zeilen unterschiedlich lang sein koennen)
Müssen für den Terminus zweidimensionales Array die Zeilen immer gleichlang sein?
`argv[1]' ist ein Char-Array (d.h. ein null-terminierter C-String).
Stimmt!
Du kannst mit einem Index auf beliebige Zeichen dieses Strings zugreifen, was du derzeit wohl machst. Alternativ kannst du mit einem Char-Pointer mittels Pointer-Arithmetik ueber den String wandern, was ein ueblicherer Stil erfahrener C-Programmierer ist. Letzteres ist fuer Nicht-C-Programmierer aber meist unintuitiver.
Ich meinte eigentlich die Funktion index bzw. rindex aus string.h.

Ich habe später zu meiner Lösung hierzu selbst noch Fragen, und ich hoffe ich kann die dann hier Stellen.
Aber noch weiss ich selbst nicht genau was ich dazu Fragen muss um es zu verstehen ;-)

Denn zumindest scheine ich keine Bytes (unnötig) zu kopieren wenn ich strtok und strlen nutze?
Siehe:
https://sourceware.org/git/?p=glibc.git ... strtok_r.c;
und
https://sourceware.org/git/?p=glibc.git ... g/strlen.c;

Aber ich meine dass ich damit mindestens einmal unnötig über den C-String zähle (iteriere?).

// Oh strtok scheint doch eine Kopie zu sein?
Zuletzt geändert von inne am 30.06.2022 19:59:43, insgesamt 2-mal geändert.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 30.06.2022 19:41:41

inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 19:14:48
Meillo hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 18:28:36
Bloss solltest du nicht die Magic Number 48 verwenden, sondern stattdessen schreiben.
Danke für den Hinweis. Was ist der Unterschied zu 48, also der Hintergrund es so zu schreiben?
Es trifft alles zu was gegen Magic Numbers im Code spricht. (Dazu kannst du auch nochmal selber recherchieren.)

Wenn eine 48 im Code steht, dann musst du eigentlich einen Kommentar dazu machen, damit man weiss was die 48 bedeutet. Ich jedenfalls wuesste nicht was 48 bedeuten soll, wenn ich den Code nicht schon verstanden habe.

Wenn dein Programm nicht mit ASCII/Latin1/Unicode arbeitet, sondern auf einem System betrieben wird, das EBCDIC als Zeichensatz verwendet, dann funktioniert der Code mit der 48 nicht mehr (weil dort die 0 an der Stelle 240 ist), wohingegen der Code mit der Character-Konstante '0' weiterhin funktioniert.

inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 19:14:48
inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 13:43:04
Ein wirklich zweidimensionales Array ist das nicht (weil die Zeilen unterschiedlich lang sein koennen)
Müssen für den Terminus zweidimensionales Array die Zeilen immer gleichlang sein?
Fuer mich ist ein zweidimensionales Array eine Flaeche. `argv' ist aber effektiv ein Kamm mit unterschiedlich langen Zinken. Genau genommen ist `argv' -- wie seine Defintion auch sagt -- ein eindimentionales Array von Char-Pointern:

Code: Alles auswählen

char *argv[]
Ein `sizeof(argv[0])' liefert dir die Groesse des ersten Elements zurueck, was die Groesse eines Pointers auf deinem System ist (vermutlich 8 Bytes).

Ein `sizeof(arr[0])' liefert dir dagegen die Groesse einer Zeile eines zweidimensionalen Arrays (char arr[3][5]) zurueck.

Man kann mit einem eindimensionalen Array von Pointern auf weitere eindimensionale Arrays aber ein zweidimensionales Array simulieren. Entscheidend ist, dass in dem Fall die einzelnen eindimensionalen Arrays an verschiedenen Stellen im Speicher liegen (koennen), waehrend bei einem richtigen zweidimensionalen Array das ganze Array an einem Stueck hintereinander liegt.

inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 19:14:48
Ich habe später zu meiner Lösung hierzu selbst noch Fragen, und ich hoffe ich kann die dann hier Stellen.
Aber noch weiss ich selbst nicht genau was ich dazu Fragen muss um es zu verstehen ;-)
Kein Problem. Vielleicht sollten wir dann den Thread aufspalten ... :roll:
inne hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 19:14:48
Denn zumindest scheine ich keine Bytes (unnötig) zu kopieren wenn ich strtok und strlen nutze?
Ja.
Use ed once in a while!

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Scripting Contest

Beitrag von inne » 02.07.2022 07:44:50

Meillo hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 19:41:41
Kein Problem. Vielleicht sollten wir dann den Thread aufspalten ... :roll:
Vlt. willst Du ab hier abtrennen. Dann könnte ich meine Frage stellen, wie man index und rindex aus string.c benutzt, um jedes Zeichen in s vom Anfang bis Position des gesucht zählt und einmal vom Ende bis zur Position. Ich meine das geht damit, weiss aber nicht wie man das in C tut, ich bekomme nur Speicherzugriffsfehler :-/

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Scripting Contest

Beitrag von Meillo » 02.07.2022 09:17:57

inne hat geschrieben: ↑ zum Beitrag ↑
02.07.2022 07:44:50
Meillo hat geschrieben: ↑ zum Beitrag ↑
30.06.2022 19:41:41
Kein Problem. Vielleicht sollten wir dann den Thread aufspalten ... :roll:
Vlt. willst Du ab hier abtrennen.
Erledigt.

inne hat geschrieben: ↑ zum Beitrag ↑
02.07.2022 07:44:50
Dann könnte ich meine Frage stellen, wie man index und rindex aus string.c benutzt, um jedes Zeichen in s vom Anfang bis Position des gesucht zählt und einmal vom Ende bis zur Position. Ich meine das geht damit, weiss aber nicht wie man das in C tut, ich bekomme nur Speicherzugriffsfehler :-/
Entscheidend ist, zu verstehen, dass man mit Pointern in C rechnen kann.

Vielleicht hilft dir dieses kleine Beispielprogramm weiter:

Code: Alles auswählen

:-/ cat index.c
#include <stdio.h>
#include <string.h>

int
main(void)
{
        char *c;
        char *s = "hello, world";

        printf("Speicheadresse von s: %p\n", s);

        if (!(c = index(s, 'o'))) {
                fprintf(stderr, "nicht gefunden\n");
                return 1;
        }
        printf("Speicheadresse von 'o': %p\n", c);
        printf("'o' ist das Zeichen mit index %ld in s\n", c - s);
        printf("das Zeichen mit index %ld in s ist: %c\n", c-s, s[c-s]);
        return 0;
}


:-/ ./index    
Speicheadresse von s: 0x2005e8
Speicheadresse von 'o': 0x2005ec
'o' ist das Zeichen mit index 4 in s
das Zeichen mit index 4 in s ist: o
Use ed once in a while!

Antworten