'Vectorfloat.Equals' dovrebbe essere riflessivo o dovrebbe seguire la semantica IEEE 754?

9

Quando si confrontano i valori in virgola mobile per l'uguaglianza, ci sono due approcci diversi:

I tipi di virgola mobile IEEE incorporati in C # ( float e double ) seguono la semantica IEEE per == e != (e gli operatori relazionali come < ) ma assicurano la riflessività per object.Equals , IEquatable<T>.Equals (e CompareTo ).

Ora considera una libreria che fornisce strutture vettoriali su float / double . Un tipo di vettore di questo tipo sovraccaricherebbe == / != e sostituirà object.Equals / IEquatable<T>.Equals .

Ciò su cui tutti sono d'accordo è che == / != dovrebbe seguire la semantica IEEE. La domanda è, se una tale libreria implementasse il metodo Equals (che è separato dagli operatori di uguaglianza) in un modo che è riflessivo o in un modo che corrisponda alla semantica IEEE.

Argomenti per l'utilizzo della semantica IEEE per Equals :

  • Segue IEEE 754
  • È (possibilmente molto) più veloce perché può trarre vantaggio dalle istruzioni SIMD

    Ho fatto una domanda a parte su StackOverflow su come esprimere l'uguaglianza riflessiva usando le istruzioni SIMD e il loro impatto sulle prestazioni: Istruzioni SIMD per il confronto dell'uguaglianza in virgola mobile

    Aggiornamento: Sembra che sia possibile implementare l'uguaglianza riflessiva in modo efficiente utilizzando tre istruzioni SIMD.

  • La documentazione di Equals non richiede riflessività quando si utilizza il floating point:

    The following statements must be true for all implementations of the Equals(Object) method. In the list, x, y, and z represent object references that are not null.

    x.Equals(x) returns true, except in cases that involve floating-point types. See ISO/IEC/IEEE 60559:2011, Information technology -- Microprocessor Systems -- Floating-Point arithmetic.

  • Se utilizzi i float come chiavi del dizionario, stai vivendo in uno stato di peccato e non dovresti aspettarti un comportamento corretto.

Argomenti per essere riflessivi:

  • È coerente con i tipi esistenti, inclusi Single , Double , Tuple e System.Numerics.Complex .

    Non conosco alcun precedente nel BCL in cui Equals segue IEEE invece di essere riflessivo. I contro esempi includono Single , Double , Tuple e System.Numerics.Complex .

  • Equals è utilizzato principalmente da contenitori e algoritmi di ricerca che si basano sulla riflessività. Per questi algoritmi un guadagno in termini di prestazioni è irrilevante se impedisce loro di funzionare. Non sacrificare la correttezza per le prestazioni.
  • Rompe tutti i set e i dizionari basati su hash, Contains , Find , IndexOf su varie raccolte / LINQ, imposta operazioni LINQ basate ( Union , Except , ecc.) se i dati contengono% valori diNaN.
  • Il codice che esegue calcoli effettivi in cui la semantica IEEE è accettabile di solito funziona su tipi concreti e utilizza == / != (o più probabilmente confronti epsilon).

    Attualmente non puoi scrivere calcoli ad alte prestazioni usando i generici poiché hai bisogno di operazioni aritmetiche per questo, ma questi non sono disponibili attraverso interfacce / metodi virtuali.

    Quindi un metodo Equals più lento non influisce sulla maggior parte del codice ad alte prestazioni.

  • È possibile fornire un metodo IeeeEquals o IeeeEqualityComparer<T> per i casi in cui è necessaria la semantica IEEE o è necessario un vantaggio in termini di prestazioni.

A mio parere questi argomenti strongmente favoriscono un'implementazione riflessiva.

Il team di CoreFX di Microsoft prevede di introdurre un tipo di vettore di questo tipo in .NET. A differenza di me preferiscono la soluzione IEEE , principalmente a causa dei vantaggi prestazionali. Dal momento che una tale decisione non sarà sicuramente cambiata dopo un rilascio finale, voglio ottenere un feedback dalla comunità, su quello che ritengo sia un grosso errore.

    
posta CodesInChaos 22.01.2016 - 18:18
fonte

2 risposte

5

Direi che il comportamento IEEE è corretto. NaN s non sono equivalenti l'un l'altro in alcun modo; corrispondono a condizioni mal definite in cui una risposta numerica non è appropriata.

Oltre ai vantaggi prestazionali derivanti dall'utilizzo dell'aritmetica IEEE che la maggior parte dei processori supportano in modo nativo, penso che ci sia un problema semantico nel dire che se isnan(x) && isnan(y) , poi x == y . Ad esempio:

// C++
double inf = std::numeric_limits<double>::infinity();
double x = 0.0 / 0.0;
double y = inf - inf;

Direi che non esiste una ragione significativa per cui si consideri x uguale a y . Difficilmente potresti concludere che sono numeri equivalenti; non sono numeri, quindi sembra solo un concetto invalido del tutto.

Inoltre, da una prospettiva di progettazione dell'API, se si sta lavorando su una libreria generica che è destinata a essere utilizzata da molti programmatori, è logico utilizzare la semantica a virgola mobile più tipica del settore. L'obiettivo di una buona libreria è di risparmiare tempo per coloro che lo usano, quindi costruire comportamenti non standard è maturo per la confusione.

    
risposta data 22.01.2016 - 20:58
fonte
0

C'è un problema: IEEE754 definisce le operazioni relazionali e l'uguaglianza in un modo che è adatto alle applicazioni numeriche. Non è adatto per l'ordinamento e l'hashing. Pertanto, se si desidera ordinare un array in base a valori numerici o se si desidera aggiungere valori numerici a un set o utilizzarli come chiavi in un dizionario, dichiarare che i valori NaN non sono consentiti oppure non utilizzare IEEE754 operazioni integrate. La tua tabella hash dovrebbe assicurarsi che tutti i NaN siano abbinati allo stesso valore e confrontare l'uno uguale all'altro.

Se si definisce Vector, è necessario prendere la decisione di progettazione se si desidera utilizzarlo solo a fini numerici o se deve essere compatibile con l'ordinamento e l'hashing. Personalmente penso che lo scopo numerico dovrebbe essere molto più importante. Se è necessario l'ordinamento / hashing, puoi scrivere una classe con Vector come membro e definire l'hashing e l'uguaglianza in quella classe nel modo che preferisci.

    
risposta data 23.01.2016 - 21:23
fonte

Leggi altre domande sui tag