Ce face math.FMA
math.FMA(x, y, z) calculează x*y + z ca și cum produsul ar avea precizie infinită și rotunjește o singură dată, la final. Expresia obișnuită rotunjește de două ori: după înmulțire și după adunare.
Diferența este mică, dar contează în calcule numerice care adună multe produse (polinoame, produse scalare). Pe procesoarele moderne FMA este și o singură instrucțiune rapidă.
Compilatorul Go poate combina singur x*y + z într-un FMA pe unele procesoare (de exemplu ARM64). O conversie explicită, float64(x*y) + z, forțează rotunjirea produsului. math.FMA garantează mereu rotunjirea unică.
Parametri
| Parametru | Descriere |
|---|---|
x, y, z |
Factorii înmulțiți (x, y) și termenul adunat (z). |
Ce returnează
Rezultatul x*y + z rotunjit o singură dată.
Exemple
Exemplul 1: Diferența față de două rotunjiri
0.1 nu se poate memora exact. Produsul 0.1 * 10 rotunjit dă exact 1, deci diferența pare 0. FMA păstrează eroarea mică a produsului și o arată.
package main
import (
"fmt"
"math"
)
func main() {
x, y, z := 0.1, 10.0, -1.0
fmt.Println(float64(x*y) + z)
fmt.Println(math.FMA(x, y, z))
}
Rezultat
0
5.551115123125783e-17
Exemplul 2: Evaluarea unui polinom (schema lui Horner)
p(x) = 2x³ − 3x² + x − 5, calculat ca ((2x − 3)x + 1)x − 5, cu câte un FMA pe pas.
package main
import (
"fmt"
"math"
)
func main() {
coef := []float64{2, -3, 1, -5}
x := 1.5
r := 0.0
for _, c := range coef {
r = math.FMA(r, x, c)
}
fmt.Println("p(1.5) =", r)
}
Rezultat
p(1.5) = -3.5
Greșeli frecvente
- Te aștepți ca
x*y + zsă dea același rezultat pe toate procesoarele: compilatorul poate folosi FMA pe unele și nu pe altele. Dacă rezultatul trebuie să fie identic, folosește explicitmath.FMAsau conversiafloat64(x*y).
Comenzi înrudite
math.Pow: math.Pow ridică x la puterea y, iar math.Pow10 calculează 10 la puterea n.math.Nextafter: Returnează următorul număr reprezentabil după x, în direcția lui y (float64 sau float32).