Problem bei ersten python versuchen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
BlackJack

Samstag 15. Oktober 2011, 20:33

Scheme-Lösungen (mit Bigloo getestet).

Problem 1:

Code: Alles auswählen

(define (dividable-by-7 n)
    (zero? (modulo n 7)))

(define (contains-digit-7 n)
    (string-contains (number->string n) "7"))

(define (print-numbers a b)
    (let ((test (lambda (n) (or (dividable-by-7 n) (contains-digit-7 n)))))
        (let loop ((i a))
            (if (<= i b)
                (begin
                    (print (if (test i) "*" i))
                    (loop (+ i 1)))))))
Problem 2:

Code: Alles auswählen

(define (print-fak-tab n)
    (let loop ((x 0) (r 1))
        (if (<= x n)
            (begin
                (print x "! = " r)
                (let ((x' (+ x 1)))
                    (loop x' (* r x')))))))
DasIch
User
Beiträge: 2437
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Samstag 15. Oktober 2011, 21:17

Hab es mal in Haskell gelöst.

Problem 1:

Code: Alles auswählen

divisibleBy7 :: Integer -> Bool
divisibleBy7 n = n `mod` 7 == 0

containsDigit7 :: Show a => a -> Bool
containsDigit7 n = '7' `elem` (show n)

printNumber :: Integer -> IO ()
printNumber n
        | divisibleBy7 n || containsDigit7 n = putStrLn "*"
        | otherwise                          = putStrLn $ show n

main :: IO ()
main = mapM_ printNumber [1..100]
Problem 2:

Code: Alles auswählen

import System.Environment (getArgs)

main :: IO ()
main = do
	args <- getArgs
	let x = getX args
        mapM_ printLine [1..x]
        where printLine n = putStrLn $ (show n) ++ "! = " ++ show (factorial n)

getX :: [String] -> Integer
getX []    = 10
getX (x:_) = read x

factorial :: Integer -> Integer
factorial n = product [1..n]
Ich komme übrigens ganz ohne Schleife aus ;)
BlackJack

Samstag 15. Oktober 2011, 21:33

@DasIch: Meine Lösung kommt auch ohne Schleifen aus. Die lokale Funktion `loop` hätte ich auch anders nennen können. :-)

Edit: Und das Ganze in Io.

Problem 1:

Code: Alles auswählen

Range

Number isDivisibleBy7 := method(self mod(7) == 0)
Number containsDigit7 := method(self asString contains("7" at(0)))

1 to(100) foreach(i, if(i isDivisibleBy7 or(i containsDigit7), "*", i) println)
Problem 2:

Code: Alles auswählen

Range
x := 1; 1 to(10) foreach(i, (i .. "! = " .. x) println; x = x * (i + 1))
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Sonntag 16. Oktober 2011, 13:10

Problem 1 in D:

Code: Alles auswählen

import std.stdio : writefln;
import std.conv : to;


bool divisible_by_7(int n) {
    return (n % 7) == 0;
}

bool contains_digit_7(int n) {
    foreach(char c; to!(string)(n)) {
        if(c == '7') { return true; }
    }
    return false;
}

void main() {
    for(int i = 1; i < 101; i++) {
        if(divisible_by_7(i) || contains_digit_7(i)) {
            writefln("*");
        } else {
            writefln("%d", i);
        }
    }
}
2 folgt evt. später, ich muss weg :P

PS:/ Ich könnte statt der schleifen auch map verwenden..
the more they change the more they stay the same
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sonntag 16. Oktober 2011, 14:08

Ok, hier mal im Commodore BASIC V2.0:

Code: Alles auswählen

10 fori=1to100:di=i/7:i$=str$(i):ou$=str$(i)
20 if(di=int(di) or mid$(i$,2,1)="7" or right$(i$,1)="7") then ou$="*"
30 print ou$;:next
Hier in Kleinbuchstaben, damit man es mittels `petcat` konvertieren kann:

Code: Alles auswählen

petcat -w2 -o test7.prg -- test7.bas 
Getestet im VICE 2.2 (x64).
Zuletzt geändert von Hyperion am Donnerstag 20. Oktober 2011, 23:07, insgesamt 1-mal geändert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3))
assert encoding_kapiert
BlackJack

Sonntag 16. Oktober 2011, 15:45

Problem 1 in CoffeeScript:

Code: Alles auswählen

#!/usr/bin/env coffee

Number :: isDivisibleBy7 = -> this % 7 is 0

Number :: containsDigit7 = -> this.toString().indexOf("7") isnt -1

test = (n) -> n.isDivisibleBy7() or n.containsDigit7()

console.log(if test i then "*" else i) for i in [1..100]
Ist der Io-Lösung sehr ähnlich.

Problem 2 zeige ich mal nicht, weil sich daraus eine Python-Lösung ziemlich 1:1 ergibt.
BlackJack

Montag 17. Oktober 2011, 09:37

Auch eine Haskell-Variante der Lösungen von mir:

Problem 1:

Code: Alles auswählen

isDivisibleBy7 = (==) 0 . mod 7

containsDigit7 = elem '7' . show

convertNumber n = if test n then "*" else show n
    where test n = isDivisibleBy7 n || containsDigit7 n

main = putStr . unlines $ map convertNumber [1..100]
Problem 2:

Code: Alles auswählen

faks = scanl (\a b -> a * succ b) 1

outputPairs r = zip r (faks r)

formatOutputPair (a,b) = show a ++ "! = " ++ show b

main = putStr . unlines $ map formatOutputPair $ outputPairs [0..10]
BlackJack

Dienstag 18. Oktober 2011, 10:27

Da Hyperion sich den C64 schon mit BASIC als Zielplattform ausgesucht hat, und mein BASIC-Programm nicht viel anders ausgesehen hätte, habe ich mal Forth auf dem Brotkasten bemüht.

Problem 1:

Code: Alles auswählen

\ Seven-Star                        bj11

: div-by-7? ( n -- ? )
  7 mod 0= ;

: contains-7? ( n -- ? )
  10 /mod 7 =  swap 7 =  or ;

: main ( -- )
  101 1 ?do
    i div-by-7?  i contains-7?  or
    if ." * " else i . then
  loop cr ;

\\ Print all numbers from 1 to 100 but
an asterisk if the number is divisible
by 7 or contains the digit 7.
Problem 2:

Code: Alles auswählen

\ Fac-Table                         bj11

: main ( -- )
  1
  9 0 ?do
    i . del ." ! = " dup u. cr
    i 1+ *
  loop
  drop ;

\\ Print a fac table. Unfortunately only
up to 8! because that is the limit for
the 16 bit integers of VolksFORTH on the
Commodore 64.
Es steht ja schon im Kommentar — mit 16-Bit-Werten kommt man bei der Fakultät nicht all zu weit. :-(
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dienstag 18. Oktober 2011, 12:24

BlackJack hat geschrieben:Da Hyperion sich den C64 schon mit BASIC als Zielplattform ausgesucht hat, und mein BASIC-Programm nicht viel anders ausgesehen hätte, habe ich mal Forth auf dem Brotkasten bemüht.
Hehe... sorry ;-)

Sag mal weißt Du evtl. wie man Modulo auf dem Brotkasten in Assembler ausdrücken kann? Ich war ja fast versucht, meine bescheidenen Assemblerkenntnisse wieder aufzufrischen, aber dafür hatte ich keine Idee.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3))
assert encoding_kapiert
lunar

Dienstag 18. Oktober 2011, 13:25

Da Haskell bereits vergeben ist, bleibt mir noch SWI-Prolog:

Code: Alles auswählen

format_number('*', X) :- 0 is X mod 7, !.
format_number('*', X) :- number_chars(X, L), memberchk('7', L), !.
format_number(S, X) :- swritef(S, "%t", [X]).

write_number(X) :- format_number(S, X), writef("%t\n", [S]).

main :- forall(between(1, 100, X), write_number(X)).
Und Problem 2:

Code: Alles auswählen

factorial(1, 0).
factorial(1, 1).
factorial(F, X) :- P is X - 1, factorial(PF, P), F is PF * X.

format_factorial(S, X) :- factorial(F, X), swritef(S, "%t! = %t", [X, F]).

write_factorial(X) :- format_factorial(S, X), writef("%t\n", [S]).

main :- forall(between(0, 10, X), write_factorial(X)).
BlackJack

Dienstag 18. Oktober 2011, 17:22

@Hyperion: Der Prozessor kann ja nur addieren, subtrahieren, und Bits verschieben. Daraus muss man sich das selber basteln. Simpelste, aber vielleicht nicht eleganteste Variante für ``a % b`` ist so lange `b` von `a` abziehen wie ``b > a`` gilt. Das was dann übrig bleibt wäre der Rest der Division. Wenn man mit zählt wie oft man das gemacht hat, bekommt man auch den ganzzahligen Anteil der Division heraus.

Trotz fehlender Eleganz wäre das bei dieser Aufgabe aber IMHO sogar im Bereich des Tolerierbaren. Das wären maximal 14 Schleifendurchläufe für 100 und 7.

Ansonsten muss man sich eine effizientere Division basteln, wo auch der Rest bei heraus fällt. Ist bei Byte/Byte auch nur eine Handvoll Befehle in einer Schleife.

Ich habe sowohl das Modulo-7 als auch das Teilen durch 10 für die Ausgabe umgangen. Ersteres, in dem ich einfach parallel einen Zähler laufen lasse um jeden 7. Durchlauf der Schleife zu erkennen. Und für die Umwandlung in eine Zeichenkette bemühe ich Routinen im BASIC-ROM:

Code: Alles auswählen

        !to "test.prg", cbm
        
        chrout = $ffd2
        strout = $ab1e
        ldf_u8 = $b3a2
        f2str  = $bddd
        
        i = $fa
        j = $fb
        
        * = $c000

        lda #1          ; i = 1
        sta i
        lda #7          ; j = 7
        sta j
loop
        dec j           ; every 7th iteration -> print asterisk
        bne .not_div_7
        lda #7
        sta j
        bne print_asterisk
.not_div_7

        ldy i           ; FAC = i
        jsr ldf_u8
        jsr f2str       ; $0100... = STR(FAC) + 0x00; A/Y = $0100
        
        lda #"7"        ; compare digits with "7"
        cmp $0101
        beq print_asterisk
        cmp $0102
        beq print_asterisk

        tya             ; print number (A/Y = $0101)
        jsr strout
        jmp print_space

print_asterisk
        lda #"*"
        jsr chrout

print_space
        lda #" "
        jsr chrout
        
        inc i           ; i++
        ldy i
        cpy #101        ; already i == 101?
        bne loop
        
        lda #13         ; print newline
        jmp chrout
Und wo ich schon dabei war, hier das Problem 2:

Code: Alles auswählen

        !to "test.prg", cbm
        
        intout = $bdcd
        strout = $ab1e
        ldf    = $bba2
        stf    = $bbd4
        ldf_u8 = $b3a2
        fltmul = $ba28
        fltout = $aabc
        
        i = $fa
        f_one  = $bfe8

        * = $c000

        ldx #4          ; n = 1.0
-       lda f_one,x
        sta n,x
        dex
        bpl -
        
        lda #0          ; i = 0
        sta i
loop
        lda #0          ; print i
        ldx i
        jsr intout
        
        lda #<txt       ; print "! ="
        ldy #>txt
        jsr strout
        
        lda #<n         ; FAC = n
        ldy #>n
        jsr ldf
        
        jsr fltout      ; print FAC + newline
        
        ldy i           ; FAC = i + 1
        iny
        jsr ldf_u8
        
        lda #<n         ; FAC *= n
        ldy #>n
        jsr fltmul
        
        ldx #<n         ; n = FAC
        ldy #>n
        jsr stf
        
        inc i           ; i++
        lda i           ; loop finished?
        cmp #11
        bne loop
        
        rts

txt:    !pet "! =", 0

n:      * = * + 5
Da mache ich auch Gebrauch von den Gleitpunktzahl-Routinen im BASIC-ROM um die Multiplikation und die Umwandlung in Dezimaldarstellung nicht selbst implementieren zu müssen. Da kann man nun natürlich streiten ob das geschummelt ist.

Ach ja: Quelltext ist für den ACME-(Cross-)Assembler.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dienstag 18. Oktober 2011, 17:47

@BlackJack: Danke :-) Gute Erklärung und auch die "Tricks" Deiner Umsetzung habe ich verstanden. Da hätte ich wirklich selber drauf kommen können!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3))
assert encoding_kapiert
BlackJack

Dienstag 18. Oktober 2011, 19:28

Nochmal zu der 6510-Assembler-Lösung von Problem 1: Wenn man die Umwandlung von `i` in Zeichen und die Ausgabe der Zeichenkette nicht mehr über das ROM macht, kommt das Programm mit einer Unterroutine zur Ausgabe eines einzelnen Zeichens als „externe“ Abhängigkeit aus und wird damit portierbarer. Dazu muss man den Code zwischen ``.not_div_7`` und ``print_asterisk`` durch dieses hier ersetzen:

Code: Alles auswählen

        lda i           ; X/Y/A = decimal digits of i
        ldx #"0"-1
        sec
-       inx
        sbc #100
        bcs -
        ldy #"9"+1
-       dey
        adc #10
        bmi -
        adc #"0"-1
        
        cpy #"7"        ; check if there is a "7"
        beq print_asterisk
        cmp #"7"
        beq print_asterisk

        pha             ; print digits in X/Y/A without leading "0"s
        cpx #"0"
        beq +
        txa
        jsr chrout
        jmp ++
+       cpy #"0"
        beq +++
++      tya
        jsr chrout
+++     pla
        jsr chrout
        jmp print_space
Insgesamt wächst dadurch der Code um 38% von 70 auf 97 Bytes. Jetzt muss ich nur noch die zweite Zählvariable durch eine gescheite Division/Modulo ersetzen, dann ist es nicht mehr so „geschummelt“.
BlackJack

Mittwoch 19. Oktober 2011, 11:24

Okay, ich denke das ist jetzt die finale 6510-Assembler-Version für Problem 1. Keine zweite Zählschleife mehr, sondern eine Modulo-Rechnung, so dass man die Grenzen jetzt im Rahmen von 1 bis 255 ändern kann, in dem man die Konstanten am Anfang setzt:

Code: Alles auswählen

        !to "test.prg", cbm
        
        chrout  = $ffd2
        
        i       = $fa
        tmp     = $fb
        
        * = $c000

        FROM    = 1
        TO      = 100
        
        ldy #FROM       ; i = FROM
        sty i
loop
        sty tmp         ; tmp = (i / 7) / 2; A = i % 7
        lda #0
        ldx #7
        clc
-       rol tmp
        rol
        cmp #7
        bcc +
        sbc #7
+       dex
        bpl -
        
        cmp #0          ; divisible by 7?
        beq print_asterisk

        lda i           ; X/Y/A = decimal digits of i
        ldx #"0"-1
        sec
-       inx
        sbc #100
        bcs -
        ldy #"9"+1
-       dey
        adc #10
        bmi -
        adc #"0"-1
        
        cpy #"7"        ; check if there is a "7"
        beq print_asterisk
        cmp #"7"
        beq print_asterisk

        pha             ; print digits in X/Y/A without leading "0"s
        cpx #"0"
        beq +
        txa
        jsr chrout
        jmp ++
+       cpy #"0"
        beq +++
++      tya
        jsr chrout
+++     pla
        jsr chrout
        jmp print_space

print_asterisk
        lda #"*"
        jsr chrout

print_space
        lda #" "
        jsr chrout
        
        inc i           ; i++
        ldy i           ; already finished?
        cpy #TO+1
        bne loop
        
        lda #13         ; print newline and return to caller
        jmp chrout
Ist jetzt bei 106 Bytes, könnte aber, da keine Abhängigkeit vom BASIC-ROM mehr besteht, 50 KiB RAM am Stück verwenden wenn man das ROM ausblendet. :-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Mittwoch 19. Oktober 2011, 13:34

BlackJack hat geschrieben: Ist jetzt bei 106 Bytes, könnte aber, da keine Abhängigkeit vom BASIC-ROM mehr besteht, 50 KiB RAM am Stück verwenden wenn man das ROM ausblendet. :-)
Fehlt nur noch die Killerapplikation, die diese 50KiB ausnutzt und diese Routine benötigt :-D

Ob wir den OP irgend wie vergrault haben? :K
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3))
assert encoding_kapiert
Antworten