Различия в C ++ / C # с плавающей и двойной

Мы конвертируем математическую библиотеку C ++ в C #. Библиотека смешивает использование чисел с плавающей запятой и двойных чисел (иногда приводя их между собой), и мы пытаемся сделать то же самое, чтобы получить те же самые результаты в C #, которые мы имели в C ++, но это оказывается очень трудным, если не невозможным

Я думаю, что проблема в одном или нескольких из следующих, но я не эксперт:

  1. Преобразование чисел с плавающей точкой в ​​двойную и двойную в плавающие вызывает непредсказуемые результаты и выполняется по-разному в C ++ и C #.

  2. C ++ и C # обрабатывают точность с плавающей точкой по-разному, и они не могут имитировать друг друга

  3. . .NET, чтобы заставить его работать как C ++, но я не могу его найти (оба 32-разрядные)

Может кто-нибудь объяснить мне возможные проблемы и, возможно, дать мне ссылку на некоторые авторитетные документы от Microsoft, которые я могу использовать, чтобы помочь объяснить ситуация и причина различий?

РЕДАКТИРОВАТЬ
Мы используем VC6 и .NET4.0

Я не могу привести примеры расчетов из-за NDA, но я могу показать некоторые цифры для различия ... вероятно, очень бесполезны сами по себе:

 8.085004000000000 (C#) vs. 
 8.084980000000000 (C++)    

 8.848165000000000 (C#) vs. 
 8.848170000000000 (C++)   

 0.015263214111328 (C#) vs. 
 0.015263900756836 (C++)  

Следует отметить, что эти числа включают сложные проблемы. Это результаты расчетов.

7
задан mskfisher 10 May 2012 в 12:37
поделиться

1 ответ

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

С другой стороны, я был бы удивлен, если бы это применялось к C#, но даже если это так, компилятору C# не нужно выбирать то же самое подмножество выражений для вычисления, что и 80-битные расширенные числа с плавающей запятой. РЕДАКТИРОВАТЬ: см. комментарий Эрика ниже.

Подробнее

Еще один пример той же проблемы с промежуточной точностью, когда компилятор использует инструкцию fmadd для умножения, за которым следует сложение в исходном коде (если в целевой архитектуре это предусмотрено). — например, PowerPC). Инструкция fmadd точно вычисляет свой промежуточный результат, тогда как обычное сложение округляет промежуточный результат.

Чтобы предотвратить это от компилятора C++, вам нужно всего лишь написать вычисления с плавающей запятой в виде трехадресного кода с использованием volatile-переменных для промежуточных результатов. Если это преобразование изменит результат программы на C++, это означает, что возникла описанная выше проблема. Но тогда вы изменили результаты на стороне С++.Вероятно, невозможно получить те же самые старые результаты C++ в C#, не читая сгенерированную сборку.

Если он немного устарел, ваш компилятор C++ может также оптимизировать вычисления с плавающей запятой, как если бы они были ассоциативными, когда это не так. Вы мало что можете с этим поделать. Это просто неправильно. Преобразование кода с тремя адресами снова помешает компилятору применить его, но опять же нет простого способа заставить компилятор C# воспроизвести старые результаты C++.

10
ответ дан 7 December 2019 в 01:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: