Operazioni matematiche ben definite per la classe cuscinetto (angolo)

3

Ho scritto una classe per rappresentare i cuscinetti (angoli con un tema nautico e uno specifico intervallo di normalizzazione). Nel programma, è necessario eseguire alcune operazioni matematiche su di essi, quindi ho sovraccaricato gli operatori +, -, * e / (questo è in C ++).

La mia domanda è: quali operatori sono matematicamente ben definiti per tale classe? O più nello specifico, nel codice seguente, ci sono degli operatori definiti che non avrei dovuto definire, e ci sono degli operatori indefiniti che avrei dovuto definire?

constexpr inline Bearing operator+(Bearing lhs, Bearing rhs) noexcept
{
    return Bearing::deg(lhs.getInDegrees() + rhs.getInDegrees());
}

constexpr inline Bearing operator-(Bearing lhs, Bearing rhs) noexcept
{
    return Bearing::deg(lhs.getInDegrees() - rhs.getInDegrees());
}

template <
    typename T,
    typename = EnableIfNumeric<T>
> constexpr inline Bearing operator*(Bearing lhs, T rhs) noexcept
{
    return Bearing::deg(lhs.getInDegrees() * static_cast<Bearing::ValueType>(rhs));
}

template <
    typename T,
    typename = EnableIfNumeric<T>
> constexpr inline Bearing operator*(T lhs, Bearing rhs) noexcept
{
    return Bearing::deg(static_cast<Bearing::ValueType>(lhs) * rhs.getInDegrees());
}


template <
    typename T,
    typename = EnableIfNumeric<T>
> constexpr inline Bearing operator/(Bearing lhs, T rhs) noexcept
{
    return Bearing::deg(lhs.getInDegrees() / static_cast<Bearing::ValueType>(rhs));
}

template <
    typename T,
    typename = EnableIfNumeric<T>
> constexpr inline Bearing operator/(T lhs, Bearing rhs) noexcept; // Intentionally not defined

constexpr inline Bearing::ValueType operator/(Bearing lhs, Bearing rhs) noexcept
{
    return lhs.getInDegrees() / rhs.getInDegrees();
}

// Bearing has value semantics
constexpr inline Bearing operator+=(Bearing lhs, Bearing rhs) noexcept; // Intentionally not defined
constexpr inline Bearing operator-=(Bearing lhs, Bearing rhs) noexcept; // Intentionally not defined
constexpr inline Bearing operator*=(Bearing lhs, Bearing rhs) noexcept; // Intentionally not defined
constexpr inline Bearing operator/=(Bearing lhs, Bearing rhs) noexcept; // Intentionally not defined


constexpr inline bool operator==(Bearing lhs, Bearing rhs) noexcept
{
    return lhs.getInDegrees() == rhs.getInDegrees();
}

constexpr inline bool operator!=(Bearing lhs, Bearing rhs) noexcept
{
    return !(lhs == rhs);
}

In parole:

  • (non mostrato nel codice precedente) Le istanze di rilevamento devono essere create dai metodi statici Bearing :: deg o Bearing :: rad, quindi le unità sono esplicite all'inizializzazione
  • I cuscinetti possono essere aggiunti o sottratti solo da altri cuscinetti
  • I cuscinetti possono essere moltiplicati solo con tipi numerici (non altri cuscinetti)
  • I cuscinetti possono essere divisi solo con tipi numerici
  • I tipi numerici non possono essere divisi per cuscinetti
  • I cuscinetti possono essere divisi da altri cuscinetti, ottenendo un valore in virgola mobile
  • I cuscinetti hanno operatori di confronto di uguaglianza, ma non operatori di confronto di disuguaglianza (poiché gli angoli si avvolgono, sia a < b eb che l = a sono veri se aeb sono cuscinetti)
  • (nota che ci sono funzioni membro per determinare le distanze assolute e in senso orario / antiorario tra un rilevamento e l'altro, quindi qualunque cosa tu voglia fare con gli operatori di confronto delle disuguaglianze dovrebbe essere possibile)

Si noti che, per "normalizzazione", intendo avvolgere gli angoli in modo che siano sempre nell'intervallo [0, 360) o [-180, 180) e che questa operazione venga eseguita solo su richiesta del cliente , non dopo ogni operazione.

P.S. I penso questa domanda è adatta per i programmatori, ma se molte persone pensano che sia più adatta per la revisione del codice, allora prenderò in considerazione l'idea di spostarla lì.

    
posta wakjah 04.02.2015 - 14:25
fonte

1 risposta

3

Dipende da cosa significa "matematicamente ben definito". Tutte le tue funzioni sono ben definite nel senso di avere una definizione unica. Tuttavia, la moltiplicazione e la divisione sono problematiche, poiché non garantiscono

(b * n) * m == b * (n * m)

(b * n) / m == b * (n / m)

dove b è un rilevamento e n è un valore numerico, ed è ciò che potresti aspettarti. Ad esempio, se b = 45° e n = m = 8 , ottieni

(b * n) / m == 360° / 8 == 0° / 8 == 0°

ma     b * (n / m) == 45 ° * 1 == 45 °

(o con moltiplicazione, imposta m = 1/8 , che mostra essenzialmente lo stesso).

Quindi, se vuoi renderlo davvero infallibile, ti suggerisco di aggiungere un operatore di conversione da un rilevamento a un float di un intervallo dato dal chiamante (ad esempio, da 0 ° a 360 ° o con moltiplicazione, o impostare da -180 ° a 180 °). La moltiplicazione e la divisione devono essere eseguite solo convertendo un rilevamento in un numero utilizzando questo intervallo, quindi applicando l'operazione e quindi convertendo nuovamente in un rilevamento. Ciò eliminerebbe ogni disambiguazione.

    
risposta data 04.02.2015 - 14:55
fonte

Leggi altre domande sui tag