Προς το περιεχόμενο

Python και διαίρεση


likoyrgos

Προτεινόμενες αναρτήσεις

Αυτά με τα __future__ δηλαδή πέρα από τις "δεσμευμένες" λέξεις παίζουν και "σινιάλα" ένα σωρό!

Γενικά όπως και με το περιβάλλον της Μ2000 δεν γίνεται να μην έχεις κάποια σινιάλα αλλά με μια απλή φόρμα π.χ. Set Future θα είχε καλύτερη εμφάνιση!

Αυτό που δείχνεις ως προτέρημα ναι έχει μια αξία με την έννοια ότι φτιάχνεις ένα κανόνα -φόρμουλα- και κάθεται παντού. Αλλά πρακτικά δεν αντιμετωπίσεις το ίδιο θέμα.

Θέλω να τσεκάρω την For για παράδειγμα αν του δώσω διάφορες τιμές και βήματα αν θα κάνει τον αριθμό επαναλήψεων που υπολογίζω. Δηλαδή

μια For i=.1 to .3 step .1...Next i  λογικά δίνει τρία βήματα 0.1, 0.2, 0.3 όμως δεν είναι σίγουρο ότι θα δώσει τρία νούμερα (μπορεί να δώσει 0.1 και 0.2 μόνο) αν ο έλεγχος δεν γίνεται με κάποια στρογγυλοποίηση!

 

Ενώ αν δώσεις μόνο ακέραιους, ή πραγματικούς χωρίς δεκαδικά -με ακέραιες τιμές- δεν έχεις ποτέ πρόβλημα ακρίβειας!


Το τσέκαρα στη 2.7.3

>>> [.1*i for i in xrange(1,3)]
[0.1, 0.2]
>>>

Δηλαδή δεν δίνει το 0.3

 

>>> [.1*i for i in xrange(1,4)]
[0.1, 0.2, 0.30000000000000004]
Δεν δίνει 0.3 !


 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 32
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Oφείλεται σε round floating point errors.

 

Μπορείς να κάνεις:

 

 

for i in range(1,4):
...     print(i/10.0)

0.1
0.2
0.3

 Ή μπορείς να χρησιμοποιήσεις τη βιβλιοθήκη numpy και την arange.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Έτσι όμως πας σε ακέραια βήματα και κάνεις αναγωγή σε δεκαδικά με διαίρεση κάθε φορά..

Στις χίλιες επαναλήψεις θα έχεις χίλιες διαιρέσεις συν χίλιες προσθέσεις.

Αν το for είχε το βήμα άμεσα τότε θα έκανε μόνο προσθέσεις.

 

Το άλλο δεν το κατάλαβα..(και δεν το ψάχνω... βάλε παράδειγμα αν θες)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Καλύτερα η linspace για float steps.

import numpy as np

a = np.linspace(0.1,0.3,3)
print(a)

http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.linspace.html#numpy.linspace

 

Αν δεν το ψάχνεις τότε τί ψάχνεσαι?

  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αυτό ήθελα, δηλαδή μια απάντηση με δυο γραμμές και όχι με ένα "Τράβα βρες το" αφού με δυο γραμμές με καλύπτεις!

:-)

 

όμως δεν έβαλες το .1 για βήμα αλλά τον αριθμό των βημάτων!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ναι αλλά αυτό δεν είναι πρόβλημα πουθενά! Και αρχαία γλώσσα να έχεις μια επανάληψη με ακέραια βήματα γίνεται. Το θέμα είναι πώς γίνεται με μη ακέραια! 

 

(ουσιαστικά δεν έχουμε ξεφύγει από την ιδέα της διαίρεσης)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ναι αλλά αυτό δεν είναι πρόβλημα πουθενά! Και αρχαία γλώσσα να έχεις μια επανάληψη με ακέραια βήματα γίνεται. Το θέμα είναι πώς γίνεται με μη ακέραια! 

 

Με μη ακέραια δε γίνεται 100% εγγυημένα και σωστά σε καμία γλώσσα χρησιμοποιώντας primitive types. Για προφανείς λόγους (ΙΕΕΕ 754).

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Υπάρχουν περιορισμοί φυσικά!

Αλλά η ιδέα μου είναι να προβλέπεις μια προσαύξηση ή το αντίστροφο ώστε να μην κάνεις το >= (αφού το ίσον έχει θέμα) αλλά μόνο το > (ή αντίστοιχα το < και όχι το <=).

Για γραφικά χρειάζεται κανείς να κάνει επαναλήψεις με νούμερα με αριθμητική δεκαδικών, αλλά δεν απαιτεί "τεράστια" ακρίβεια!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Οκ. 

Πάντως με τη συζήτηση έτρεξα και μερικά σκριπτάκια Python...και αυτό είναι το ζουμί..να λέμε αλλά και να κάνουμε, να βλέπουμε και να μαθαίνουμε!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Το 0.3 δεν έχει ακριβή αναπαράσταση στο δυαδικό σύστημα.

Ως floating point, το nibble 0011 επαναλαμβάνεται ατέρμονα.

Ο compiler στρογγυλοποιεί το τελευταίο bit προς τα πάνω και

στην αναπαράσταση το τελευταίο nibble γίνεται 0100,

εξ ου και το μεγαλύτερο αποτέλεσμα του 0.3.

 

Η C/C++ έχει το ίδιο πρόβλημα.

Η στρογγυλοποίηση μπορεί να ελεγχθεί μέσω εντολών που ελέγχουν την floating point unit (FPU).

Π.χ., αν επιλεγεί στρογυλλοποίηση προς τα κάτω, το αποτέλεσμα θα είναι 0.29999999999999999

διότι το τελευταίο nibble θα μείνει όπως είναι.

 

 

Διδιακτικό είναι το παρακάτω απόσπασμα:

int main()
{
double temp;
bool equal;
  
temp = 0.2*3.0;
equal = (temp==0.6);
printf("%.16e \t %d \n", temp, equal );
printf("%.16e \t %.16e \t %d \n", 0.2*3.0, 0.6, 0.2*3.0==0.6) );
 
return 0;
}

Παραδόξως, τo temp=0.2*3 ΔΕΝ ισούται με 0.6 !!!

Το 0.6 στην πραγματικότητα το "βλέπει" ως 0.59999999999999998

και το 0.2*3 δίνει 0.60000000000000009 .

 

Στη .NET υπάρχουν εντολές (Math.Round(...) κλπ) με την οποίες μπορεί να επιλεγεί σε ποιο ψηφίο του αριθμού θα γίνει στρογγυλοποίηση και προς ποιά κατεύθυνση. Π.χ., μπορεί να στρογγυλοποιηθεί το παραπάνω στο π.χ. 4ο δεκαδικό και να δίνει 0.6 . Δυστυχώς αυτό αφορά μόνον μεμονωμένες πράξεις/παραστάσεις.

 

Υπάρχει κάποιος τρόπος να γίνει αυτό καθολικά;

δηλ. να ρυθμιστεί ώστε ΟΛΕΣ οι πράξεις να στρογγυλεύουν με τον ίδιο τρόπο;

 

 

Στην fortran το παραπάνω δίνει σωστό αποτέλεσμα αλλά μόνο εν μέρη :

program trial
implicit none
real(8)::temp
temp = 0.2_8*3_8;print *, temp, 0.2_8*3, (0.2_8*3==temp), (0.2_8*3==0.6_8)

end program

Είτε σε απλή, είτε σε διπλή ακρίβεια, δίνει

-  temp=0.6 που είναι το σωστό (σε αντίθεση με τη C/C++),

-  για το 0.2*3 τυπώνει σωστά ότι ισούται με 0.6 (σε αντίθεση με τη C/C++),

-  το 0.2*3==0.6 το δίνει ψευδές (αντίθετα με ότι τυπώνει, και σε συμφωνία με τη C/C++)...

 

 

Οσο για τα γραφικά, collision detection κ.α., ποτέ δεν γίνεται υπολογισμός με αριθμητική δεκαδικών.

Οι βασικές τεχνικές για τη διατήρηση της ευρωστίας είναι

- χρήση ανοχών,

- "παχιά" επίπεδα,

- "παχιά" σώματα,

- κοινός διαμοιρασμός υπολογισμών,

- αριθμητική διαστημάτων (interval arithmetic),

- ακριβείς και ημιακριβείς υπολογισμοί (αντιμετώπιση των floats ως integers κλπ),

- αριθμητική αυξημένης ακρίβειας σε κατηγορήματα (predicates)

 

-

Επεξ/σία από V.I.Smirnov
  • Like 3
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Στη Μ2000 παίζει λάθος στο κανονικό =, το == κάνει στρογγυλοποίηση στο 10ο δεκαδικό (αυθαίρετα το έβαλα, αλλά σημασία στον προγραμματισμό έχει το εργαλείο και μετά μαθαίνεις τι κάνει, ότι δηλαδή λέμε και εδώ για την python, ο κάθε κατασκευαστής κάνει ότι θέλει)

temp = 0.2*3
print temp, (0.2*3==temp), (0.2*3==0.6)
print temp, (0.2*3=temp), (0.2*3=0.6)  '  To (0.2*3=0.6) βγαίνει λάθος

 

Για τα γραφικά ασφαλώς θα χρησιμοποιηθούν floating point αριθμητικά, έχω γράψει στο κώδικα της Μ2000  περιστροφή Bitmap που με την χρήση γραμμικής παρεμβολής δημιουργεί ενδιάμεσα χρώματα. Έχω και ρουτίνα χωρίς floating point αριθμητικά για να περιστρέφω τα sprites γιατί εκεί έχω pixels διάφανα και το ενδιάμεσο δεν έχει νόημα.. (θέλουμε και γρηγοράδα).

Αυτό εδώ το τμήμα υπολογίζει τέσσερις συντελεστές που πολλαπλασιάζουν τέσσερα pixels. Το σφάλμα το παίρνω με αφαίρεση! Δηλαδή μετακινώ το σφάλμα του xf στο xf1. Τα mmx και mmy είναι ακέραια. το sx το υπολογίζω πιο πριν  sx = temp_image_x / pws

και είναι όλα single.

   xf = Abs((sx - CSng(mmx)))
             xf1 = 1! - xf
                      yf = Abs((sy - CSng(mmy)))
                      yf1 = 1! - yf
Στην απλή περιστροφή έχουμε όλα τα νούμερα  σε long. Τα mmx καιι mmy είναι οι δείκτες για το προς περιστροφή
                         mmx = temp_image_x \ pw
.............
                        bDib1(screen_x, screen_y) = bDib(mmx, mmy)
                    
Οι ρουτίνες βρίσκονται στο Pichandler.bas (ο κώδικας δίνεται μαζί)
 
Τα παχιά στρώματα που γράφεις είναι το snap...δηλαδή η γειτνίαση με μια κάνναβο, δηλαδή υπάρχουν τακτικώς οριοθετημένα σημεία και κάθε επιλογή μας θα πάει στο κοντινότερο (αν έχει να κάνει με "εισαγωγή"). Όμως ένας κύκλος ή μια καμπύλη δεν ακολουθεί το snap αλλιώς θα παίρναμε ένα γελοίο σχήμα!
 
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Οι τεχνικές για τη διατήρηση της ευρωστίας είναι αυτές που έγραψα.

Δεν είναι κατάλληλες για κάθε περίπτωση αλλά αυτές είναι.

Σε ότι αφορά τα "παχιά σώματα", χρησιμοποιούνται σε collision detection.

Π.χ. ένας κύκλος αντιμετωπίζεται ως τόρος, μια ευθεία ως "σωλήνας" κλπ,

εισάγοντας έτσι εμμέσως ανοχές για τον υπολογισμό.

Τα παχιά επίπεδα το ίδιο

Οι ταχύτεροι τρόποι είναι η χρήση βελτιστοποιημένων predicates και η ακέραια αριθμητική των floating points,

ο δε ευκολότερος είναι η χρήση ανοχών.

 

-

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το δέχομαι. Πάνω κάτω η υπέρθεση, να κάνεις κάτι που δυσκολεύεται σε ένα χώρο να μπει σε μεγαλύτερο μετράει. Να γιατί ήθελα η For βάσει του βήματος και των αρχικών και τελικών τιμών να μπορεί να καθορίσει μια τελική τιμή ελαφρώς διαφορετική ώστε η τελική τιμή αν είναι δυνατόν να βγει αλλά σε καμία περίπτωση μια μεγαλύτερη από αυτή (μέσα στην επανάληψη). Το έχω πετύχει σπάζοντας το θέμα σε υποπεριπτώσεις!

 

Αλλά ας γυρίσουμε στο θέμα μας. Η ευκολία της Python να δίνει μια συνάρτηση για κάθε τιμή σημαίνει και την ευκολία να δίνει άλλο αποτέλεσμα βάσει επιλογής που δεν φαίνεται πάνω στο κώδικα στο σημείο που εφαρμόζουμε την συνάρτηση. Αυτό σημαίνει ότι είναι απαραίτητο να ακολουθεί κανείς το κώδικα για να γνωρίζει τι τιμή βάζει ή να δεχτεί στο όνομα να βάζει κάποιο αναγνωριστικό ώστε διαβάζοντας τη γραμμή κώδικα που έχει τη συνάρτηση να ξέρει ότι θα πάρει ακέραιο αποτέλεσμα ή όχι.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...