Ответ 1
Значение -2.611429
не может быть представлено с использованием 64-битной с плавающей запятой. При компиляции в 32-битном режиме значение вместо этого будет использовать 80-битную (расширенную точность).
У меня есть этот крошечный фрагмент кода
double s = -2.6114289999999998;
double s7 = Math.Round(s, 7);
double s5 = Math.Round(s, 5);
double s6 = Math.Round(s, 6);
С платформой = любой процессор, я получаю
s7: -2.611429
s5: -2.61143
s6: -2.611429
С платформой = x64 я получаю
s7: -2.6114289999999998
s5: -2.61143
s6: -2.6114289999999998
Почему? (Результат скопирован из окна VS Locals)
Весь фрагмент кода:
private void btnAlign_Click(object sender, EventArgs e)
{
double s = -2.6114289999999998;
double s7 = Math.Round(s, 7);
double s5 = Math.Round(s, 5);
double s6 = Math.Round(s, 6);
}
Значение -2.611429
не может быть представлено с использованием 64-битной с плавающей запятой. При компиляции в 32-битном режиме значение вместо этого будет использовать 80-битную (расширенную точность).
В x64 используется SSU2 FPU, а на x86 используется xpp x90.
Возможно (хотя и не рекомендуется) изменять точность x87 так же, как точность SSE2 (т.е. использовать более низкую точность).
Вы можете сделать это с помощью _controlfp()
API.
Следующая программа демонстрирует. Запустите эту программу в режиме x86, и вы увидите, как использование _controlfp(0x00030000, 0x00020000)
приводит к тому, что вывод будет схожим с (но не совсем таким же!) Как версия x64:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApp3
{
class Program
{
static void Main()
{
double s = -2.6114289999999998;
Console.WriteLine(Math.Round(s, 7).ToString("R")); // -2.611429
if (!Environment.Is64BitProcess)
_controlfp(0x00030000, 0x00020000);
Console.WriteLine(Math.Round(s, 7).ToString("R")); // -2.61142897605896
}
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern uint _controlfp(uint newcw, uint mask);
}
}
Однако вам не следует обходиться с FPU таким образом (и если вы это сделаете, вы должны вернуться к предыдущей настройке как можно скорее).
В соответствии со спецификацией языка CSharp 3.0 может иметь место следующее:
Более подробную информацию см. в главе 4.1.6.
Операции с плавающей запятой могут выполняться с большей точностью, чем тип результата операции. Например, некоторые аппаратные архитектуры поддерживают "расширенный" или "длинный двойной" тип с плавающей запятой с большим диапазоном и точностью, чем двойной тип, и неявно выполняют все операции с плавающей запятой, используя этот более высокий тип точности. Только при чрезмерной стоимости производительности могут быть созданы такие аппаратные архитектуры для выполнения операций с плавающей запятой с меньшей точностью и вместо того, чтобы требовать, чтобы реализация лишилась производительности и точности, С# позволяет использовать более высокий тип точности для всех операций с плавающей запятой, Помимо предоставления более точных результатов, это редко имеет какие-либо измеримые эффекты. Однако в выражениях вида x * y/z, где умножение дает результат, выходящий за пределы двойного диапазона, но последующее деление возвращает временный результат обратно в двойной диапазон, тот факт, что выражение оценивается в более высоком диапазон может привести к тому, что конечный результат будет создан вместо бесконечности.
Вкратце: спецификация С# фактически заявляет, что аппаратные архитектуры могут иметь некоторое влияние на типы с плавающей точкой (Double, Float).
Отвечено здесь: fooobar.com/info/299800/...
x64 управляемый код будет использовать SSE для вычисления double/float вместо x87 FPU при использовании управляемого кода x86.