-2

Ques:контроль переполнения и потери точности в то время как умножение парного

У меня есть большое количество чисел с плавающей точкой (~ 10000 номеров), каждый из которых имеет 6 цифр после запятой. Теперь умножение всех этих чисел даст около 60 000 цифр. Но двойной диапазон - только 15 цифр. Выходной продукт должен иметь 6 цифр точности после десятичной.

мой подход:

Я думал умножения этих чисел на 10^6, а затем умножая их, а затем, разделив их на 10^12.

Я также думал о умножении этих чисел с помощью массивов, чтобы хранить их цифры, а затем преобразовывать их в десятичные числа. Но это также кажется громоздким и не может дать правильный результат.

Есть ли альтернативный более простой способ сделать это?

+0

Я использую C++ для своего кода. :) – bnks452

+0

http://stackoverflow.com/q/2568446/327083 –

+0

http://www.google.com/search?q=c%2B%2B+arbitrary+precision –

ответ

2

Я думал о умножении этих чисел на 10^6, а затем их умножении и последующем их делении на 10^12.

Это приведет только к дальнейшей потере точности. В плавающей точке большие числа представлены примерно так же, как небольшие числа. Увеличение числа ваших чисел означает, что вы делаете 19999 умножений (и одно деление) вместо 9999 умножений; это не волшебным образом дает вам более значимые цифры.

Эта манипуляция была бы полезной только в том случае, если бы это предотвратило попадание частичного продукта в субнормальную территорию (и в этом случае рекомендуется умножить на две силы, чтобы избежать потери точности из-за умножения). В вашем вопросе нет никаких указаний на то, что это происходит, нет набора данных примера, никакого кода, поэтому можно предоставить общее объяснение ниже:

Умножение с плавающей запятой очень хорошо ведет себя, когда оно не переполняется или переполняется , В первом порядке вы можете предположить, что относительные неточности складываются, так что умножение значений 10000 дает результат, который 9999 машинных эпсилонов от математического результата в относительных терминах (*).

Решение проблемы, как указано (без кода, без набора данных), заключается в использовании более широкого типа с плавающей запятой для промежуточных умножений. Это решает проблемы с потоком или переполнением и дает вам относительную точность в конечном результате, так что после округления до исходного типа с плавающей запятой продукт не соответствует не более чем одному ULP.

В зависимости от вашего языка программирования такой более широкий тип с плавающей запятой may be available aslong double. Для 10000 умножений 80-разрядный «расширенный двойной» формат, широко доступный в x86-процессорах, значительно улучшит ситуацию, и вы вряд ли увидите разницу в производительности, если ваш компилятор сопоставляет этот 80-битный формат с плавающей точкой тип. В противном случае вам придется использовать программную реализацию, такую ​​как MPFR' с произвольной точностью с плавающей запятой или двойной двойной формат.

(*) В действительности относительные погрешности соединены так, что реальная оценка относительной погрешности больше похожа на (1 + ε) - 1 где ε - эпсилон машины. Кроме того, в действительности относительные ошибки часто отменяют друг друга, так что вы можете ожидать, что фактическая относительная ошибка будет расти как квадратный корень теоретической максимальной ошибки.

+0

"Это манипулирование было бы полезно, если бы оно предотвращали попадание частичного продукта в субнормальную территорию (и в этом случае рекомендуется умножить на две силы, чтобы избежать потери точности из-за умножения) ». Не могли бы вы объяснить, что это значит? – bnks452

+0

@ bnks452 Я бы предпочел, чтобы вы предоставили пример набора данных, и я мог бы сказать вам, что вам не нужно беспокоиться о субнормальных явлениях. В противном случае существует определение [здесь] (https://en.wikipedia.org/wiki/Denormal_number), и предложение, относящееся к обсуждению, - «это позволяет вычислению медленно терять точность, когда результат мал». что, хотя вы не получаете нуль, когда частичный продукт является субнормальным числом, конечный результат может быть менее точным, чем ожидалось. –

+0

Умножая числа на 10^6, я хотел хранить их как целые числа и умножать, потому что мой набор данных состоит из чисел с плавающей запятой < 1 and > 0 и имеет 6 цифр после десятичного числа. например, 0,123456, 0,986173 и т. д. Здесь около 10000 номеров, и я должен получить вывод, имеющий 6 цифр после десятичного числа. – bnks452