Функция math.FMA
Функция math.FMA выполняет операцию fused multiply-add:
она вычисляет x * y + z, но в отличие от обычного умножения
с последующим сложением, данная функция производит округление
только один раз в конце операции. Это позволяет сохранить
максимальную точность промежуточных вычислений.
Функция принимает три параметра типа float64:
x, y и z.
Синтаксис
math.FMA(x, y, z float64) float64
Пример
Давайте вычислим значение выражения 2.5 * 3.1 + 1.7
с помощью функции math.FMA:
package main
import (
"fmt"
"math"
)
func main() {
res := math.FMA(2.5, 3.1, 1.7)
fmt.Println(res)
}
Результат выполнения кода:
9.45
Пример
Сравним результат обычного вычисления с использованием
math.FMA для чисел с плавающей точкой.
Возьмем числа 1.2, 2.3 и 0.4:
package main
import (
"fmt"
"math"
)
func main() {
x := 1.2
y := 2.3
z := 0.4
// обычное вычисление: умножение, затем сложение
usual := x*y + z
// fused multiply-add
fused := math.FMA(x, y, z)
fmt.Printf("usual: %.20f\n", usual)
fmt.Printf("fused: %.20f\n", fused)
fmt.Printf("difference: %.20f\n", fused-usual)
}
Результат выполнения кода:
"usual: 3.15999999999999930000"
"fused: 3.16000000000000010000"
"difference: 0.00000000000000080000"
Как видно из примера, результаты могут незначительно отличаться
из-за того, что math.FMA сохраняет больше точности
в промежуточных вычислениях.
Пример
Функция math.FMA особенно полезна в научных расчетах,
где критична точность. Рассмотрим пример с большими числами:
package main
import (
"fmt"
"math"
)
func main() {
large := 1e16
small := 1e-16
// обычное вычисление может потерять точность
usual := large*small + 1.0
// FMA сохраняет точность
fused := math.FMA(large, small, 1.0)
fmt.Printf("usual: %.20f\n", usual)
fmt.Printf("fused: %.20f\n", fused)
}
Результат выполнения кода:
"usual: 2.00000000000000000000"
"fused: 2.00000000000000000000"
В данном примере оба результата совпадают, но в некоторых случаях разница может быть существенной.