Прецизионные различия в matlab и С++

Я пытаюсь сделать тесты эквивалентности по алгоритму, написанному на С++ и в Matlab. Алгоритм содержит какой-то цикл во времени и работает более 1000 раз. Он имеет арифметические операции и некоторые математические функции.

Я загружаю исходные входы на обе платформы вручную (например, a = 1.767, b = 6.65,...), и когда я проверяю шестнадцатеричные представления этих вводов, они одинаковы. Поэтому никаких проблем для ввода. И получить выходы С++ в matlab с помощью текстового файла с 16 десятичными цифрами. (я использую оператор setprecision (32) "

Но здесь возникает проблема; хотя после 614-го шага обоих кодов все результаты точно совпадают, на этапе 615 я получаю разницу примерно 2.xxx..xxe-19? И после этого шага ошибка становится больше и больше, а в конце прогонов она составляет около 5.xx..xxe-14.

0x3ff1 3e42 a211 6cca --- > [функция С++] --- > 0x3ff4 7619 7005 5a42

0x3ff1 3e42 a211 6cca --- > [Функция MATLAB] --- > ans

ans - 0x3ff4 7619 7005 5a42

= 2.xxx..xxe-19

Я искал, как Matlab ведет числа и нашел действительно интересные вещи, такие как "denormalized mantissa". Хотя realmin около e-308, денормализация мантиссы Matlab имеет наименьшее реальное число около e-324. В дальнейшем matlab содержит еще много цифр для "pi" или "exp (1)", чем для С++.

С другой стороны, помощь Matlab говорит, что независимо от формата, который он отображает, Matlab использует внутреннюю двойную точность.

Итак, я бы очень признателен, если кто-то объяснит, в чем заключается точная причина этих различий? Как мы можем сделать тесты эквивалентности для matlab и С++?

Ответ 1

A аналогичная дискуссия произошла раньше, было заключено, что IEEE 754 допускает ошибка в последнем бите для трансцендентных функций (cos, sin, exp и т.д.). Таким образом, вы не можете ожидать точно таких же результатов между MATLAB и C (даже не тот же C-код, скомпилированный в разных компиляторах).

Ответ 2

В процессоре x86 есть одна вещь о числах с плавающей запятой. Внутренне блок с плавающей точкой использует регистры, которые составляют 10 байтов, то есть 80 бит. Кроме того, у CPU есть параметр, который указывает, должны ли выполняться вычисления с плавающей запятой с 32 битами (float), 64 битами (double) или точностью до 80 бит. Менее точное значение означает выполнение операций с плавающей запятой. (32-битный режим был популярным для видеоигр, где скорость превзошла точность).

Из этого я помню, что я отслеживал ошибку в библиотеке вычислений (dll), которая при том же вводе не давала того же результата, была ли она запущена из тестового исполняемого файла С++ или из MatLab.. Кроме того, этого не произошло в режиме отладки, только в Release!

Окончательный вывод заключался в том, что MatLab действительно установил точность с плавающей запятой процессора до 80 бит, тогда как наш тестовый исполняемый файл не выполнил (и оставил точность 64-битного значения по умолчанию). Кроме того, это рассогласование вычислений не было выполнено в режиме отладки, потому что все переменные были записаны в память в 64 бита переменных double и перезагружены оттуда после этого, сбрасывая дополнительные 16 бит. В режиме Release некоторые переменные были оптимизированы (не записаны в память), и все вычисления выполнялись только с помощью регистров с плавающей запятой только на 80 бит, сохраняя дополнительные 16 бит ненулевое значение.

Не знаю, помогает ли это, но, возможно, стоит знать.

Ответ 3

Я, возможно, отстал отсюда, и вы, возможно, уже исследовали эту возможность, но возможно, что существуют различия между С++ и Matlab в том, как функции математической библиотеки (sin() cos() и exp() которые вы упоминаете) реализованы внутри страны. В конечном счете, какое-то функциональное приближение должно использоваться для генерации значений функций, и если есть какая-то разница между этими методами, то, по-видимому, возможно, что это проявляется в виде числовой ошибки округления при большом количестве итераций.

Этот вопрос в основном охватывает то, что я пытаюсь предложить Как C вычисляет sin() и другие математические функции?