Perché i valori di ritorno delle funzioni di confronto in molte lingue sono definiti in modo approssimativo?

4

Molte lingue definiscono che le funzioni di confronto devono restituire QUALSIASI valore negativo, zero o QUALSIASI valore positivo. C'è qualche ragione per cui non dovrebbe essere definito chiaramente come -1 0 e 1? Un'ampia gamma di possibili valori di ritorno aiuta gli algoritmi più avanzati a lavorare in modo più efficiente? Se sì, quali algoritmi funzionano in questo modo?

    
posta Shane 13.01.2015 - 09:25
fonte

4 risposte

7

Se si consente alla funzione di confronto di restituire qualsiasi valore negativo anziché esattamente -1, ciò può rendere un'implementazione più semplice. Ad esempio, puoi scrivere

return this.position - that.position;

invece di dover scrivere

if(this.position == that.position) {
    return 0;
}
else if(this.position < that.position) {
    return -1;
} else
    return 1;
}

(L'alternativa è di usare un operatore, come <=> di Perl, che genera esattamente -1, 0 o 1. Ma è più facile definire un'API più lenta che ottenere un nuovo operatore nella tua lingua, a meno che tu non sia " Larry Wall.)

    
risposta data 13.01.2015 - 09:31
fonte
3

Per i casi di utilizzo semplice, consente un'implementazione molto banale:

public int compare(Child a, Child b) {
    return a.age - b.age;
}
//sort children by age to determine who babysits 

Nel frattempo, se è necessaria una logica più complessa, è ancora semplice restituire i numeri magici -1 , 0 o 1 una volta determinato l'ordine.

Come dice CodesInChaos nei commenti, il metodo di sottrazione non riesce a contenere eventuali overflow che possono verificarsi. Le librerie di carattere generale richiedono maggiore robustezza e complessità nei loro confronti.

Ecco un paio di implementazioni testate in battaglia:

  1. Java Integer.compare() :

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    
  2. Mono Int32.CompareTo() :

    public int CompareTo (object value)
    {
        if (value == null)
            return 1;
    
        if (!(value is System.Int32))
            throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
    
        int xv = (int) value;
        if (m_value == xv)
            return 0;
        if (m_value > xv)
            return 1;
        else
            return -1;
    }
    

Come puoi vedere, entrambi applicano la logica richiesta e restituiscono il numero magico appropriato.

    
risposta data 13.01.2015 - 09:31
fonte
0

La semantica del valore di ritorno non ha quasi nulla a che fare con l'implementazione. Questa specifica non lascia spazio a comportamenti non specificati ed è staticamente verificabile.

Se si specifica che il valore di ritorno è un numero arbitrario, questo può essere controllato staticamente - il compilatore può facilmente verificare che la funzione non restituisca una stringa. In caso contrario, la verifica statica è impossibile: i valori che non rientrano nell'intervallo specificato non possono essere eliminati staticamente per i tipi non enumerati. Pertanto il codice chiamante dovrà gestire valori non specificati in runtime, emettendo un comportamento più non specificato.

Possiamo tranquillamente dire che questa decisione è stata presa per imitare il comportamento descritto da Jörg nel suo commento - specifica completa, ogni opzione coperta.

    
risposta data 13.01.2015 - 22:11
fonte
-1

È perché quando fai un confronto di solito stai prendendo la differenza di due valori e invece di sprecare più tempo e fatica nel mappare il risultato in {-1,0,1} , lascia semplicemente il risultato e definisci la funzione come tale. Ad esempio x.comparedTo(y) = 0 significa che se x e y sono entrambi 5 , (5 - 5) = 0 ma se x = 100 e y = 150 , (100 - 150) = -50 e quindi x < y .

    
risposta data 13.01.2015 - 09:35
fonte

Leggi altre domande sui tag