Предполагая, что все вероятности в разумных пределах, скажем, [2^{- 63}, 2^{63}], вы можете накапливать продукт, как это:
double prod(double *d, int n, int64_t *expo) {
*expo = 0;
double ans = 1;
for (int i = 0; i < n; i++) {
ans *= d[i];
if (!(i % 16)) {
int foo = 0;
ans = frexp(ans, &foo);
expo += foo;
}
}
}
Продукт затем в пределах n/2 ulp возвращаемого значения времени 2^{*expo
}. Этот код достаточно прост для векторизации, и также довольно легко написать альтернативу, более быструю, frexp
для этого особого случая, который просто выполняет бит-скрининг и игнорирует NaNs/бесконечности/нули/субнормальные значения.
Если ваша платформа поддерживает захват арифметики с плавающей запятой, и ваш ввод, как известно, лежит в разумном, но неизвестном диапазоне, вы можете адаптировать шаг с минимальным воздействием на большие n
, добавив обработчики ловушек для переполнения и переполнения , Это, вероятно, проще всего сделать, если вы напишете как процедуру продукта, так и обработчик ловушки на ассемблере вашей платформы.
Если вместо этого вы добавляете логарифмы, вы теряете значительную точность, сначала беря логарифмы, а во-вторых, суммируя их, что вам может или не нужно. Хуже то, что вы также теряете значительное количество скорости, вычисляя столько логарифмов.
благодарю вас за помощь ура :-) –