Float и двойная точность в c # - PullRequest
       32

Float и двойная точность в c #

0 голосов
/ 29 сентября 2010

Здесь есть небольшая проблема с кодом умножения матриц.Кажется, я теряю точность при умножении больших матриц (мой код отлично работает на маленьких матрицах).

Мой цикл выглядит следующим образом:

for (int j = 0; j < columns; j++)
{
    float[] column = otherMatrix.Column(j);
    for (int i = 0; i < rows; i++)
    {
        double s = 0;
        for (int k = 0; k < size; k++)
            s += this[i,k] * ((double) column[k]);
        result[i, j] = (float)s;
    }
}

Как вы можете видеть, я форсирую (double) точность, чтобы быть уверенным, что я не теряю точность при умножении двух моих чисел.

Глядя на код IL, я вижу два conv.r8, которые заставляют меня думать, что код IL имеет точность с плавающей запятой к двойнойпреобразование в нем.

Однако, когда я запускаю его и смотрю на разборку (машина x86), я вижу следующее:

0000024e  fld         dword ptr [edx+eax*4+8] 
00000252  fmulp       st(1),st 
00000254  fadd        qword ptr [ebp-64h] 
00000257  fstp        qword ptr [ebp-20h] 

Это заставляет меня думать, что JIT думал, чтопоскольку я уже умножаю числа с плавающей запятой, он должен использовать не умножение с двойной точностью, а умножение с одинарной точностью, что дает мне ошибки, которые я отслеживал.

Я прав?Есть ли способ заставить это умножение двойной точности?

Спасибо

Ответы [ 3 ]

3 голосов
/ 29 сентября 2010

Я думаю вы неправильно интерпретируете сборку.Я считаю, что FMULP всегда работает с 80-битными регистрами.Я был бы удивлен, увидев, что JIT делает неправильную вещь здесь.

Я предлагаю вам использовать мои DoubleConverter, чтобы записать точные значения до и послеарифметика.Таким образом, вы должны лучше понять, что происходит.

0 голосов
/ 29 сентября 2010

Во-первых, есть ли причина, по которой вы не можете использовать десятичную дробь?Десятичные дроби поддерживают необходимую точность любого числа и не имеют надоедливых «ближайших двоичных представлений мантиссы», которые могут возникнуть с плавающей точкой, что может привести к ошибкам xy = z + - .0000000000 ... 0000001.

От MSDN:

Тип десятичного значения представляет десятичные числа в диапазоне от положительных 79,228,162,514,264,337,593,543,950,335 до отрицательных 79,228,162,514,264,337,593,543,950,335.Тип десятичного значения подходит для финансовых расчетов, требующих большого количества значащих целых и дробных цифр и без ошибок округления.Тип Decimal не устраняет необходимость округления.Скорее, это сводит к минимуму ошибки из-за округления.

Если это не удастся, попробуйте привести обе стороны к удвоению перед умножением.float * double может привести к двойному результату, но, поскольку ваш double является замаскированным float по сравнению с другим float, компилятор может игнорировать желаемую точность, «зная», что два числа с плавающей точкой не сделают double.

0 голосов
/ 29 сентября 2010

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

...