Frage Wie man Zahlen verschiedener Typen multipliziert / teilt / addiert / subtrahiert?


Ich arbeite gerade an der zweiten Ausgabe des Rust-Handbuchs und entscheide mich, den klassischen Celsius-zu-Fahrenheit-Konverter zu bauen:

fn c_to_f(c: f32) -> f32 {
    return ( c * ( 9/5 ) ) + 32;
}

Kompilieren mit cargo build wird den Kompilierzeitfehler ergeben:

error[E0277]: the trait bound `f32: std::ops::Mul<{integer}>` is not satisfied
 --> src/main.rs:2:12
  |
2 |     return (c * (9 / 5)) + 32;
  |            ^^^^^^^^^^^^^ the trait `std::ops::Mul<{integer}>` is not implemented for `f32`
  |
  = note: no implementation for `f32 * {integer}`

Als ein neuer Rust-Programmierer ist meine Interpretation, dass ich float- und integer-Typen nicht multiplizieren kann. Ich löste das, indem ich alle meine Konstanten Fließkommawerte machte:

fn c_to_f(c: f32) -> f32 {
    return ( c * ( 9.0/5.0 ) ) + 32.0;
}

Das lässt mich zurückhaltend sein. Aus C / C ++ / Java / Python kommend war es überraschend zu erfahren, dass man nicht einfach Zahlen verschiedener Typen arithmetisch ausführen kann. Ist es das Richtige, sie einfach in den gleichen Typ zu konvertieren, wie ich es hier getan habe?


5
2018-06-14 18:34


Ursprung


Antworten:


TL; DR: as ist der gebräuchlichste Weg, um zwischen den primitiven numerischen Typen zu konvertieren, aber es erfordert Denken.

fn c_to_f(c: f32) -> f32 {
    (c * (9 as f32 / 5 as f32)) + 32 as f32
}

In diesem Beispiel ist es jedoch sinnvoller, Fließkommaliterale zu verwenden, um damit zu beginnen:

fn c_to_f(c: f32) -> f32 {
    (c * (9. / 5.)) + 32.
}

Das echt Problem ist, dass gemischte Arithmetik etwas kompliziert ist.

Wenn du multiplizierst1 ein T durch eine T, erwarten Sie im Allgemeinen ein Ergebnis des Typs Tzumindest bei den Grundtypen.

Beim Mischen von Typen gibt es jedoch einige Schwierigkeiten:

  • Unterschriften mischen,
  • Mischgenauigkeit.

Also zum Beispiel, was ist das ideale Ergebnis von i8 * u32? Der kleinste Typ, der die gesamte Menge umfassen kann i8 und u32 Werte sind a i64. Sollte das das Ergebnis sein?

Als ein anderes Beispiel, was ist das ideale Ergebnis von f32 * i32? Der kleinste Typ, der die gesamte Menge umfassen kann f32 und i32 Werte sind a f64. Sollte das das Ergebnis sein?

Ich finde die Idee, ein solches zu haben Erweiterung eher verwirrend. Es hat auch Auswirkungen auf die Leistung (Operationen auf f32 kann viel schneller als Operationen sein f64, einmal vektorisiert).

Aufgrund dieser Probleme verlangt Rust für den Moment, dass Sie explizit angeben: Welchen Typ soll die Berechnung enthalten? Welcher Typ ist für Ihre spezielle Situation sinnvoll?

Und dann richtig anwenden, mit asund überlegen Sie, welcher Rundungsmodus angewendet werden soll (.round(), .ceil(), .floor() oder .trunc() wenn man vom Fließpunkt zum Integral geht).

1  Hinzufügen, Subtrahieren und Dividieren funktionieren auf ähnliche Weise.


8
2018-06-14 18:47