Το θέμα είναι να βγαίνουν τίμια τα ζάρια και όχι απλά να πάρουμε μια λύση. Το θέμα είναι ότι η random είναι δίκαια από τη φύση της γεγονός που αποδεικνύεται και στα ποσοστά που εξάγονται με τον ακόλουθο κώδικα.
#!/usr/bin/env python
import random
# Αρχικοποίηση ζαριού
rolls = {"1":0, "2":0, "3":0, "4":0, "5":0 ,"6":0}
# Ερώτηση για αριθμό ρίψεων
n=int(input("Δώσε αριθμό ρίψεων : "))
# Ρίψη ζαρίας
for i in range(1,n+1):
roll=random.randint(1,100)
if roll in range(1,7):
rolls[str(roll)]+=1
# Στατιστικά ζαριάς
percent=0
for k in range (1,7):
percentage=100*rolls[str(k)]/sum(rolls.values())
print("Το",k,"ήρθε",rolls[str(k)],f"φορές με πιθανότητα {percentage:.2f}","%")
percent += percentage
print("\nΠραγματοποιήθηκαν",sum(rolls.values()),"επιτυχείς ρίψεις, σε ποσοστό",f"{sum(rolls.values())/n:.2f}%")
There are no guarantees as to the quality of the random sequence produced. In the past, some implementations of rand() have had serious shortcomings in the randomness, distribution and period of the sequence produced (in one well-known example, the low-order bit simply alternated between 1 and 0 between calls). rand() is not recommended for serious random-number generation needs
To POSIX έχει επίσης βγάλει μια μορφή της rand() σαν obsolete. Πηγή Η C++ την έχει αντικαταστατήσει με ένα πολύ πολύπλοκο σύστημα που όμως δίνει “καλούς” τυχαίους αριθμούς. Δεν μπορεί να την αφαιρέσει, μιας και πολλά προγράμματα εξαρτώνται από αυτήν, αλλά αντικατέστησε την std::random_shuffle που την χρησιμοποιεί με την std::shuffle. Και έχοντας υπόψην τον δισταγμό να αφαιρούνται πράγματα από την γλώσσα, αυτό μας λέει πολλά.
Κατά συνέπεια η χρήση της rand() μπορεί να είναι ή να μην είναι “δίκαια” καθώς εξαρτάτε απο την υλοποίηση. Σε παλιές μηχανές τύπου spectrum ή κακή φύση της ήταν ορατή στα παιγνίδια. Σήμερα το πρόβλημα το κρύβει η μεγάλη τιμή της RAND_MAX.
Η κουβέντα αυτή βέβαια μέχρι στιγμής αφορά την C και το POSIX και όχι γλώσσες όπως την Python, που όμως την χρησιμοποιούν κάτω από το καπάκι. Η Python μπορεί να έχει μια καλή μηχανή που να σου δίνει καλή κατανομή, μπορεί και όχι. Δεν έχω δει τον κώδικα.
Αλλά ας θεωρήσουμε πως είναι μια καλή συνάρτηση (οι διαφορές είναι μικρές). Η πρόκληση είναι να την θεωρήσεις σωστή και να την χρησιμοποιήσεις έμμεσα. Αν φτιάξεις ένα ζάρι με 6 πλευρές από ένα ζάρι με 10, που είναι η πρόκληση θα έχεις ένα καλύτερο κριτήριο για να αποφασίσεις.
Είστε ωραίοι! Μια επισήμανση μόνο, αν τρέξει το πρόγραμμα με λίγες ρίψεις και δεν τύχει να έρθει κάποιο νούμερο από τα πρώτα έξι, τότε χτυπάει error για μηδενικό παρονομαστή.
#!/usr/bin/env python
import random
# Αρχικοποίηση ζαριού
rolls = {"1":0, "2":0, "3":0, "4":0, "5":0 ,"6":0}
# Ερώτηση για αριθμό ρίψεων με αποκλεισμό λανθασμένων εισαγωγών
while True:
try:
n=int(input("Δώσε αριθμό ρίψεων : "))
if n>0:break
else:
print("Ο αριθμός πρέπει να είναι > 0")
continue
except ValueError:
print("Δεν είναι αριθμός, ξαναπροσπάθηστε")
# Ρίψη ζαρίας
for i in range(1,n+1):
roll=random.randint(1,100)
if roll in range(1,7):
rolls[str(roll)]+=1
# Στατιστικά ζαριάς
percent=0
for k in range (1,7):
if rolls[str(k)]!=0 :
if rolls[str(k)]==1:
times="ά"
else:times="ές"
percentage=100*rolls[str(k)]/sum(rolls.values())
print("Το",k,"ήρθε",rolls[str(k)],f"φορ{times} με πιθανότητα {percentage:.2f}","%")
percent += percentage
if sum(rolls.values()) == 0:
print("\nΔεν υπήρξαν επιτυχείς ρίψεις")
elif sum(rolls.values())==1:
print("\nΠραγματοποιήθηκε 1 επιτυχής ρίψη")
else:
print("\nΠραγματοποιήθηκαν", sum(rolls.values()), "επιτυχείς ρίψεις, σε ποσοστό", f"{100*sum(rolls.values()) / n:3.2f}%")
Έκανα ένα μικρό fine tuning για να εμφανίζεται και ενικός αριθμός στην περίπτωση που έχουμε μια ρίψη από κάθε αριθμό. Πάντως στατιστικά η τιμιότητα του ζαριού εξαρτάται από το στατιστικό δείγμα. Επομένως το ζάρι που θα το ρίξουμε λίγες φορές είναι λιγότερο τίμιο από ένα που θα το ρίξουμε σε ένα στατιστικά σημαντικό αριθμό ρίψεων.
Με βάση τις προηγούμενες απαντήσεις, υλοποίηση με υπορουτίνες σε **FORTRAN(f90)**. Απλά για να συγκρίνετε ταχύτητες σε μεγάλο αριθμό ρίψεων :
PROGRAM dice
IMPLICIT NONE
INTEGER :: times
INTEGER, DIMENSION(6):: zari
REAL :: pithanotita
CALL prompt(times)
CALL zeroes(zari)
CALL ripsi(times,zari)
CALL apotelesmata(zari,pithanotita)
END PROGRAM dice
SUBROUTINE prompt(times)
IMPLICIT NONE
INTEGER :: times
PRINT *, 'Poses fores na paixei to zari?:'
READ *, times
IF (times .LE. 0) THEN
PRINT*,"Akyro noumero, program terminated."
STOP
ELSE IF (times .GT. 0) THEN
RETURN
END IF
RETURN
END SUBROUTINE prompt
SUBROUTINE zeroes(zari)
IMPLICIT NONE
INTEGER :: i
INTEGER, DIMENSION(6) :: zari
DO i=1,6
zari(i)=0
END DO
RETURN
END SUBROUTINE zeroes
SUBROUTINE ripsi(times,zari)
IMPLICIT NONE
INTEGER :: times,i,x,seed
INTEGER, DIMENSION(6):: zari
REAL :: r
CALL SYSTEM_CLOCK(seed)
CALL SRAND(seed)
DO i=1,times
x = 1+floor(100*RAND())
IF (x .LT. 7) THEN
zari(x)=zari(x)+1
END IF
END DO
RETURN
END SUBROUTINE ripsi
SUBROUTINE apotelesmata(zari,pithanotita)
IMPLICIT NONE
INTEGER, DIMENSION(6):: zari
INTEGER :: i
REAL:: pithanotita
DO i=1,6
IF (sum(zari) .EQ. 0) THEN
PRINT*,"Kanenas arithmos den vgike"
RETURN
END IF
pithanotita=real(zari(i))/real(SUM(zari))*100
IF (zari(i) .EQ. 1) THEN
PRINT*,"To",i,"irthe",zari(i),"fora me pithanotita ",pithanotita,"%"
ELSE IF (zari(i) .EQ. 0) THEN
CONTINUE
ELSE
PRINT*,"To",i,"irthe",zari(i),"fores me pithanotita",pithanotita,"%"
END IF
END DO
RETURN
END SUBROUTINE apotelesmata