Библиотека для строгой математики с плавающей точкой в ​​.NET - PullRequest
9 голосов
/ 13 января 2010

У меня есть алгоритм / вычисления в Java и модульный тест для него. Модульный тест ожидает результат с некоторой точностью / дельта. Теперь я перенес алгоритм в .NET и хотел бы использовать тот же модульный тест. Я работаю с двойным типом данных.

Проблема заключается в том, что Java использует строгий fp (64 бита) для некоторых операций в классе Math. Где, так как .NET всегда использует FPU / CPU (80 бит). .NET точнее и быстрее. Java более предсказуема.

Поскольку мой алгоритм циклический и использует результаты предыдущего раунда, ошибка / разница / большая точность накапливается слишком сильно. Я не полагаюсь на скорость (для юнит-теста). И я рад использовать точность .NET в производстве, но я хотел бы проверить реализацию.

Рассмотрим это из JDK


public final class Math {
    public static double atan2(double y, double x) {
    return StrictMath.atan2(y, x); // default impl. delegates to StrictMath
    }
}

Я ищу библиотеку или технику для использования строгой FP в .NET .

Упреждающий комментарий: Я понимаю формат IEEE 754 и тот факт, что число с плавающей точкой не является точным десятичным числом или дробью. Нет десятичной дроби, нет BigInt или BigNumber. Пожалуйста, не отвечайте, спасибо.

Ответы [ 2 ]

4 голосов
/ 22 октября 2013

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

Можно эмулировать "строгий" режим, вставляя избыточные броски везде , но это кажется хрупким, специфичным для C # и утомительнымрешение.

32-битный JIT испускает инструкции x87, а 64-битный JIT испускает инструкции SSE.Это верно как для Microsoft, так и для Mono.В отличие от x87, плавающая арифметика SSE воспроизводима .

Я считаю, что System.Math просто вызывает эквивалентные функции времени выполнения C, хотя я не смог войти в сборку, чтобы проверить это (есликто-то знает, как это сделать, пожалуйста, проверьте!).Среда выполнения C использует SSE-версии трансцендентных функций, когда это возможно, за исключением нескольких случаев, в частности, sqrt (но написание обертки с помощью встроенных функций для этого тривиально).По самой природе SSE они должны быть воспроизводимыми. Можно программно определить, использует ли среда выполнения C свою реализацию SSE, а не x87 .

Для остальных трансцендентных функций, недоступных в SSE (fmod, sinh, cosh, tanh),возможно, они не вызывают проблем с воспроизводимостью, если на x87 не выполняется дальнейшая операция с их результатом.

Короче говоря, использование 64-битного CLR должно решить проблему арифметики;для трансцендентных функций большинство уже реализовано в SSE, и я даже не уверен, что это необходимо, если вы не выполните арифметику x87 с результатами.

2 голосов
/ 10 марта 2010

К сожалению, нет способа обеспечить строгость FP в C #, .Net CLR просто не в состоянии выполнять вычисления с меньшей точностью, чем максимально возможный.

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

Однако не является ли strictfp необязательным? Не могли бы вы выполнить свой Java-код без модификатора strictfp? Затем он должен использовать тот же механизм с плавающей запятой, что и .Net

Таким образом, вместо того, чтобы заставлять .Net использовать strictfp и проверять, чтобы он получал те же значения, что и ваш код Java, вы можете заставить Java не использовать strictfp и проверять, чтобы он потом получал то же, что и .Net код.

...