Почему Math.Exp дает разные результаты между 32-битным и 64-битным, с одинаковым вводом и тем же оборудованием - PullRequest
11 голосов
/ 26 октября 2010

Я использую .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 / публикации / файлы / ECMA-ST / Ecma-335.pdf (12.1.3 Обработка типов данных с плавающей запятой)

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

Ответы [ 2 ]

4 голосов
/ 26 октября 2010

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

3 голосов
/ 26 октября 2010

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

...