Может ли точность с плавающей точкой зависеть от потока? - PullRequest
6 голосов
/ 17 мая 2010

У меня есть небольшой трехмерный векторный класс в C # 3.0, основанный на struct, в которой в качестве базовой единицы используется double.

Пример: значение y одного вектора равно

-20.0 straight

Я вычитаю вектор со значением y

10.094999999999965

Значение для y, которое я ожидаю, равно

-30.094999999999963         (1)

Вместо этого я получаю

-30.094999313354492         (2)

Когда я делаю все вычисления в одном потоке, я получаю (1). Также отладчик и VS Quick-Watch возвращает (1). Но когда я запускаю несколько итераций в одном потоке, а затем вызываю функцию из другого потока, результатом является (2). Теперь отладчик также возвращает (2)!

Мы должны помнить, что .NET JIT может записывать значения обратно в память (веб-сайт Jon Skeet), что снижает точность с 80 бит (FPU) до 64 бит (двойная). Однако точность (2) намного ниже этой.

Класс вектор выглядит примерно так

public struct Vector3d
{
  private readonly double _x, _y, _z;
  ...
  public static Vector3d operator -(Vector3d v1, Vector3d v2)
  {
      return new Vector3d(v1._x - v2._x, v1._y - v2._y, v1._z - v2._z);
  }  
}

Вычисление так же просто, как это

Vector3d pos41 = pos4 - pos1;

1 Ответ

5 голосов
/ 17 мая 2010

Да, я считаю, что результат может зависеть от потока.

Я предполагаю, что вы используете DirectX в какой-то момент в вашем коде - и это устанавливает точность для FPU, и я считаю, что он устанавливает его для каждого потока.

Чтобы исправить это, используйте флаг D3DCREATE_FPU_PRESERVE при вызове CreateDevice. Обратите внимание, что это может оказать влияние на производительность. Управляемый эквивалент: CreateFlags.FpuPreserve.

(См. этот связанный вопрос . Я не предлагал, чтобы этот вопрос был закрыт как дубликат, так как они по крайней мере выглядят немного по-другому. Наличие обоих должно помогите найти ответ.)

...