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

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

Δημοσ.

Καλησπέρα, χρόνια πολλά & καλή χρονια!

 

Θα μπορούσε κάποιος που γνωρίζει να επιβεβαιώσει πως η παρακάτω γραμμή κώδικα λειτουργεί as intended όταν θέλουμε να βεβαιώσουμε πως τα off & maxOffset είναι πάντα θετικά και πως το off βρίσκεται μεταξύ 0 (συμπεριλαμβανομένου) και maxOffset?

static inline bool _is_valid_offset( float off, const float maxOffset )
{
	// weird negations in order to avoid float equality comparisons
	return	!(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
}
Σωστό τον βλέπω και λειτουργεί σωστά σε διάφορες δοκιμές που έχω κάνει, αλλά αναρωτιέμαι μήπως υπάρχει κάποιο corner-case που μου έχει ξεφύγει (και μου σκάσει σε κάποιο μεταγενέστερο στάδιο και ψάχνομαι). Το έχω κάνει έτσι για να αποφύγω περιττή (?) χρήση delta, fabsf() κλπ.

 

Επίσης αν μπορεί να απλοποιηθεί περαιτέρω η έκφραση, ευχαρίστως να την ακούσω και να την υιοθετήσω.

 

Thanks!

Δημοσ.

Επειδή πρόκειται για floats θέλω να αποφύγω απευθείας συγκρίσεις ισότητας.

 

Δηλαδή, το: !(off < 0)

είναι σαν το: (off >= 0)

αλλά αποφεύγει την ισότητα με το 0.

 

Έπειτα, χωρίς χρήση delta και fabsf() πως αλλιώς θα μπορούσα να ελέγχω για θετικό off αν πάρει π.χ. την τιμή -0.0001?

Δημοσ.

Καλησπέρα  και Καλή χρονιά.

 

Κάνοντας έναν πίνακα αληθείας βρίσκουμε ότι:

       sign        ||       ret-value       |
off  |  maxOffset  ||   A   |   B   |   C   |
=====+=============++=======+=======+=======+
 +   |     +       ||   1   |   1   | 0{off>max} or 1{off<max}
 +   |     -       ||   1   |   0   |///////|
 +   |     0       ||   1   |   1   |   0   |
 -   |     +       ||   0   |///////|///////|
 -   |     -       ||   0   |///////|///////|
 -   |     0       ||   0   |///////|///////|
 0   |     +       ||   1   |   1   |   1   |
 0   |     -       ||   1   |   0   |///////|
 0   |     0       ||   1   |   1   |   1   |

Όπως βλέπουμε οι εγκυρες καταστάσεις, αυτές που θα αποτιμηθούν είναι στις περιπτώσεις όπου

  • off > 0 && maxOffset > 0 && off < maxOffset
  • off = 0 && maxOffset > 0
  • off = maxOffset = 0

Απλά πρέπει να διευκρινήσεις το 'θετικά'. Θετικά με μηδέν ή χωρίς; Έτσι όπως το έκανες έχεις συμπεριλάβει και το μηδέν στις έγκυρες τιμές των off και maxOffset. Διευκρινίζεις για το off (μπορεί να πάρει μηδενική τιμή), όχι όμως και για το maxOffset. Άρα όλα παίζονται στην τρίτη κουκίδα παραπάνω, όπου το off είναι ή δεν είναι στο πεδίο ορισμού που επιθυμείς.

Δημοσ.


_declspec(noinline)
bool _is_valid_offset( float off, const float maxOffset )
{
// weird negations in order to avoid float equality comparisons
return !(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
}
_declspec(noinline)
bool _is_valid_offset_1(float off, float maxOffset)
{
return off >= 0.f && off <= maxOffset;
}

int main()
{
float pi = 3.1415f;
int r1 = _is_valid_offset(pi,10.f);
int r2 = _is_valid_offset_1(pi,10.f);
printf("just compite them %d %d", r1,r2);
return 0;
}


_declspec(noinline)
bool _is_valid_offset( float off, const float maxOffset )
{
00E11270 xorps xmm2,xmm2
// weird negations in order to avoid float equality comparisons
return !(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
00E11273 comiss xmm2,xmm0
00E11276 ja _is_valid_offset+15h (0E11285h)
00E11278 comiss xmm2,xmm1
00E1127B ja _is_valid_offset+15h (0E11285h)
00E1127D comiss xmm0,xmm1
00E11280 ja _is_valid_offset+15h (0E11285h)
00E11282 mov al,1
}
00E11284 ret
// weird negations in order to avoid float equality comparisons
return !(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
00E11285 xor al,al
}
00E11287 ret
--- No source file -------------------------------------------------------------
00E11288 int 3
00E11289 int 3
00E1128A int 3
00E1128B int 3
00E1128C int 3
00E1128D int 3
00E1128E int 3
00E1128F int 3
--- c:\users\papi\documents\visual studio 2012\projects\cppgtest\cppgtest\main.cpp
return off >= 0.f && off <= maxOffset;
00E11290 comiss xmm0,dword ptr ds:[0E1324Ch]
00E11297 jb _is_valid_offset_1+11h (0E112A1h)
00E11299 comiss xmm1,xmm0
00E1129C jb _is_valid_offset_1+11h (0E112A1h)
00E1129E mov al,1
}
00E112A0 ret
return off >= 0.f && off <= maxOffset;
00E112A1 xor al,al
}
00E112A3 ret
Δημοσ.

@gon1332: respect!

 

Θέλω το 0 να λογίζεται στα "θετικά" αλλά τελικά θέλω το off να μην μπορεί να γίνει ίσο με maxOffset. Δηλαδή το off να μπορεί να πάρει τιμές στο εύρος [0, maxOffset)... δλδ από 0 included έως maxOffset excluded... π.χ. (maxOffset - κάποιο_delta).

 

Οπότε ή πρέπει να προσθέσω και 4ο όρο στην έκφραση...

static inline bool _is_valid_offset( float off, const float maxOffset )
{
	// weird negations in order to avoid float equality comparisons
	return off != maxOffset && !(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
}
ή να το αφήσω στον caller της συνάρτησης να περνάει αυτό το "κάποιο_delta" στο 2ο όρισμα της συνάρτησης.

Π.χ.

    ...
    x    = read_float();
    xmax = read_float();
    ...
    if ( _is_valid_offset(x, max-0.003) ) ...
Σωστά τα λεώ; (γιατί έχω κι ένα κεφάλι καζάνι αυτή τη στιγμή).
Δημοσ.

 

	// weird negations in order to avoid float equality comparisons
	return	!(off < 0) && !(maxOffset < 0) && !(off > maxOffset);

 

Δεν εχω καταλαβει το τι θες, αλλα τα NOT τι τα θες;

Επειδή πρόκειται για floats θέλω να αποφύγω απευθείας συγκρίσεις ισότητας.

 

Δηλαδή, το: !(off < 0

είναι σαν το: (off >= 0)

αλλά αποφεύγει την ισότητα με το 0.

 

Έπειτα, χωρίς χρήση delta και fabsf() πως αλλιώς θα μπορούσα να ελέγχω για θετικό off αν πάρει π.χ. την τιμή -0.0001?

Και εγώ έχω την ίδια απορία. Τι κερδίζεις με τον συνδυασμό < και ! σε σχέση με το >= ?

 

Το κλασικό return (off >= 0.0f) && (mO >= 0.0f) && (off < mO) δεν θα είχε το ίδιο αποτέλεσμα με ακριβώς τα ίδια corner-case προβλήματα ?

Δημοσ.

@παπι: γράφαμε μαζί, η ανησυχία μου είναι ανακριβή αποτελέσματα σε τυχόν corner-cases που δεν τα έχω προβλέψει.

 

Και εγώ έχω την ίδια απορία. Τι κερδίζεις με τον συνδυασμό < και ! σε σχέση με το >= ?

 

Το κλασικό return (off >= 0.0f) && (mO >= 0.0f) && (off < mO) δεν θα είχε το ίδιο αποτέλεσμα με ακριβώς τα ίδια corner-case προβλήματα ?

Μπορεί να λέω βλακείες γιατί πραγματικά είμαι θολωμένος αυτή τη στιγμή (για αυτό και πόσταρα για βοήθεια) αλλά με τα ! δεν αποφεύγω αναξιόπιστο αποτέλεσμα του >= ?

Δημοσ.

 

Μπορεί να λέω βλακείες γιατί πραγματικά είμαι θολωμένος αυτή τη στιγμή (για αυτό και πόσταρα για βοήθεια) αλλά με τα ! δεν αποφεύγω αναξιόπιστο αποτέλεσμα του >= ?

 

Εαν δεις το asm που ποσταρα, θα δεις οτι το NOT το μονο που κανει ειναι να αλλαζει θεση στους registers. 

Δημοσ.

@παπι: γράφαμε μαζί, η ανησυχία μου είναι ανακριβή αποτελέσματα σε τυχόν corner-cases που δεν τα έχω προβλέψει.

 

 

Μπορεί να λέω βλακείες γιατί πραγματικά είμαι θολωμένος αυτή τη στιγμή (για αυτό και πόσταρα για βοήθεια) αλλά με τα ! δεν αποφεύγω αναξιόπιστο αποτέλεσμα του >= ?

 

 

Εαν δεις το asm που ποσταρα, θα δεις οτι το NOT το μονο που κανει ειναι να αλλαζει θεση στους registers.

Όπως λέει ο παπί, με το NOT δεν κερδίζεις κάτι και ίσα ίσα χάνεις γιατί το negation μπορεί να αφήσει να περάσει κάποια χαζομάρα όπως πχ: (τραβηγμένο παράδειγμα το δέχομαι)

 

#include <stdio.h>

static inline int _is_1( float off, const float maxOffset )
{
	return	!(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
}

static inline int _is_2( float off, const float maxOffset )
{
	return (off > 0.0f) && (off < maxOffset);
}

int main(void)
{
	float f= 0.0 / 0.0;
	float m=6;

	printf("%d\n",_is_1(f,m));
	printf("%d\n",_is_2(f,m));

	return 0;
}
Έξοδος:
1
0
Το negation δίνει αποτέλεσμα 1 ακόμα και όταν η σύγκριση αποτυγχάνει λόγω NaN, inf, κτλ.
Δημοσ.

Οπότε είναι x-platform safe να τη γράψω με τον καθιερωμένο τρόπο την έκφραση;

Δηλαδή με >=, <=, κλπ ?

Αν είναι 100% safe σε όλες τις περιπτώσεις δεν το ξέρω αλλά ο τρόπος που πρότεινε ο παπί είναι σίγουρα καλύτερος από τον τρόπο με το negation.

 

Το off >= 0.0f εγγυάται ότι το offset είναι πραγματικός αριθμός και όχι NaN, κτλ και ότι είναι θετικό ή μηδέν (ο αριθμός 0 αναπαριστάται σωστά όση μικρή ακρίβεια και να έχει ο float οπότε η συγκεκριμένη equality σύγκριση δεν θα πρέπει να έχει ποτέ πρόβλημα) και το off < maxOffset κομμάτι ότι το offset είναι μικρότερο του ορίου (και κατά συνέπεια ότι το μέγιστο όριο είναι θετικό).

 

Edit: Αν το κάνεις έτσι ώστε ο caller να παρέχει κάποιο δέλτα όπως είπες, θα πρέπει να λάβεις μέτρα ώστε αυτό να είναι ικανοποιητικό για το range που έχεις.

Δημοσ.

Οκ παιδιά thanks! Το συγκεκριμένο θα το κάνω με το καθιερωμένο (off >= 0 και off < maxOffset) και ο Θεός βοηθός :lol:

 

ΥΓ. Κάποια στιγμή μάλλον θα χρειαστώ και implementation αμιγούς ισότητας με fabsf() και delta, αλλά έχω ακόμα καιρό για αυτό.

Δημοσ.

@gon1332: respect!

 

Θέλω το 0 να λογίζεται στα "θετικά" αλλά τελικά θέλω το off να μην μπορεί να γίνει ίσο με maxOffset. Δηλαδή το off να μπορεί να πάρει τιμές στο εύρος [0, maxOffset)... δλδ από 0 included έως maxOffset excluded... π.χ. (maxOffset - κάποιο_delta).

 

Οπότε ή πρέπει να προσθέσω και 4ο όρο στην έκφραση...

static inline bool _is_valid_offset( float off, const float maxOffset )
{
	// weird negations in order to avoid float equality comparisons
	return off != maxOffset && !(off < 0) && !(maxOffset < 0) && !(off > maxOffset);
}
ή να το αφήσω στον caller της συνάρτησης να περνάει αυτό το "κάποιο_delta" στο 2ο όρισμα της συνάρτησης.

Π.χ.

    ...
    x    = read_float();
    xmax = read_float();
    ...
    if ( _is_valid_offset(x, max-0.003) ) ...
Σωστά τα λεώ; (γιατί έχω κι ένα κεφάλι καζάνι αυτή τη στιγμή).

 

 

Οι συνθήκες φαίνεται πλέον να δουλεύουν σωστά. Τώρα όσον αφορά το user-level definition of delta, δεν είμαι πολύ σίγουρος γι' αυτό. Πιστεύω ότι με αυτόν τον τρόπο η λειτουργικότητα της συνάρτησης θα εξαρτάται αποκλειστικά από τον χρήστη, κάνοντας πολλές φορές δύσκολο το debugging. Γνώμη μου είναι να υπάρει μία Α προστασία εκ των έσω, διευκολύνοντας το χειριστή του API. Όλα αυτά αν κατάλαβα του τί περίπου θέλεις να κάνεις.

 

Φιλικά.

Δημοσ.

@gon:

 

Βασικά το πρόβλημά μου δεν ήταν η λογική των συνθηκών, αλλά τυχόν ανακρίβειες που μπορεί να προκύψουν από ελέγχους ισότητας/ανισότητας μεταξύ float. Τελικά την έκανα με τον απλό τρόπο, αφού παπι & ημίθεος την βρήκαν παπαδιά τη μακαρονάδα που έγραψα... και ο θεός βοηθός τώρα :lol:

static inline bool _float_is_zero_to_nomax( float f, float max )
{
	return f >= 0.0f && f < max;
}

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

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

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

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

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

Σύνδεση

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

Συνδεθείτε τώρα
  • Δημιουργία νέου...