Почему Math.Exp дает разные результаты между 32-битными и 64-битными, с тем же входом, одним и тем же оборудованием

Я использую .NET 2.0 с PlatformTarget x64 и x86. Я даю Math.Exp тот же номер ввода, и он возвращает разные результаты на любой платформе.

MSDN заявляет, что вы не можете полагаться на литерал/парсинг Double, чтобы представлять одинаковое число между платформами, но я думаю, что мое использование Int64BitsToDouble ниже позволяет избежать этой проблемы и гарантирует тот же ввод Math.Exp на обеих платформах.

Мой вопрос в том, почему результаты разные? Я бы подумал, что:

  • вход сохраняется таким же образом (двойная/64-битная точность)
  • FPU будет выполнять одни и те же вычисления независимо от битовой мощности процессора.
  • вывод сохраняется таким же образом

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

Кто-нибудь знает, что происходит под капотом?

double d = BitConverter.Int64BitsToDouble(-4648784593573222648L); // same as Double.Parse("-0.0068846153846153849") but with no concern about losing digits in conversion
Debug.Assert(d.ToString("G17") == "-0.0068846153846153849"
    && BitConverter.DoubleToInt64Bits(d) == -4648784593573222648L); // true on both 32 & 64 bit

double exp = Math.Exp(d);

Console.WriteLine("{0:G17} = {1}", exp, BitConverter.DoubleToInt64Bits(exp));
// 64-bit: 0.99313902928727449 = 4607120620669726947
// 32-bit: 0.9931390292872746  = 4607120620669726948

Результаты согласованы на обеих платформах с включенным или выключенным JIT.

[изменить]

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

http://www.manicai.net/comp/debugging/fpudiff/ говорит, что:

Итак, 32-разрядный использует 80-битные регистры FPU, 64-разрядный использует 128-разрядные регистры SSE.

И в стандарте CLI говорится, что удвоения могут быть представлены с более высокой точностью, если аппаратное обеспечение поддерживает его:

[Обоснование: эта конструкция позволяет CLI выбирать высокопроизводительное представление для конкретной платформы для с плавающей запятой, пока они не будут помещены в места хранения. Например, он может уйти переменные с плавающей запятой в аппаратных регистрах, которые обеспечивают большую точность, чем запрашивал пользователь. На Раздел я 69 В то же время генераторы CIL могут принуждать операции к соблюдению языковых правил для представлений посредством использование инструкций преобразования. конечное обоснование]

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf (12.1.3 Обработка типов данных с плавающей запятой)

Я думаю, что это то, что здесь происходит, потому что результаты различаются после Double standard 15 цифр точности. Результат 64-разрядной Math.Exp более точен (у него есть дополнительная цифра), потому что внутренне 64-разрядный .NET использует регистр FPU с большей точностью, чем регистр FPU, используемый 32-битным .NET.

Ответ 1

Да ошибки округления, и это фактически НЕ то же самое оборудование. 32-разрядная версия предназначена для разных наборов инструкций и размеров регистров.

Ответ 2

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