Почему 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 выбирать высокопроизводительное представление для конкретной платформы для чисел с плавающей запятой, пока они не будут размещены в местах хранения. Например, он может оставить переменные с плавающей запятой в аппаратных регистрах, которые обеспечивают большую точность, чем запросил пользователь. В то же время на Разделе I 69 генераторы CIL могут заставить операции соблюдать языковые правила для представлений с помощью инструкций преобразования. окончание]
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf (12.1.3 Обработка типов данных с плавающей точкой)
Я думаю, что это то, что происходит здесь, потому что результаты отличаются от стандартных 15 цифр точности Double. 64-битный результат Math.Exp является более точным (он имеет дополнительную цифру), потому что внутренне 64-битный .NET использует регистр FPU с большей точностью, чем регистр FPU, используемый 32-битным .NET.