Аппаратные ошибки вычислений с вещественными числами
{
System.Collections.Generic.LinkedList<Double> returnedValue=new System.Collections.Generic.LinkedList<Double>();
Single xMin=X1<X2 ? X1:X2, xMax=X1>X2 ? X1:X2;
if(Step<=0)
{
throw new ArgumentException(String.Format("Invalid parameter 'Step'={0}(Step>0)", Step));
}
else
{
Single x;
for(x=xMin; x!=xMax;x=x+Step)
{
returnedValue.AddLast(new ArgumentAndFunctionClass(x, this.MathParser.Parse(this.MathParser.FunctionToCalculatedExpression(Function, PlotterClass.ArgName, x), PlotterClass.IsRadians
)
)
);
}
}
return returnedValue;
}
{
System.Collections.Generic.LinkedList<Double> returnedValue=new System.Collections.Generic.LinkedList<Double>();
Decimal xMin=X1<X2 ? X1:X2, xMax=X1>X2 ? X1:X2;
if(Step<=0)
{
throw new ArgumentException(String.Format("Invalid parameter 'Step'={0}(Step>0)", Step));
}
else
{
Decimal x;
for(x=xMin; x!=xMax;x=x+Step)
{
returnedValue.AddLast(new ArgumentAndFunctionClass(x, this.MathParser.Parse(this.MathParser.FunctionToCalculatedExpression(Function, PlotterClass.ArgName, x), PlotterClass.IsRadians
)
)
);
}
}
return returnedValue;
}
десятичная система тоже "как-то странно" справляется с простейшей задачей,
разделить 1 на 3, это 1/3 - и все! А в десятичной системе приходится писать 0.3333333333333333 .... - и все равно это меньше, чем 1/3 !
:-)
Что же касается процессорного времени - то его лучше беречь, когда ясно как это делать.
Тип Decimal реализует десятичную арифметику на двоичной базе.
То есть делает то, что должны были сделать вы, как программист, при использовании Double.
То что числа с плавающей точкой имеют ограниченную точность - должно быть учтено в алгоритме.
Вам надо округлять до нужного значения или не ставить строгой проверки условия.
Возникает закономерный вопрос - если есть такой хороший тип Decimal - зачем же тогда поддерживать устаревший (который только на старых процессорах и нужен был :-) ) тип Double?
И ответ на него очень прост - вычисления с Decimal медленнее, так как процессору приходится соблюдать точность, которая может быть и не нужна вовсе (в конкретной задаче).
В дот нет обязательно использование типа Decimal только для операций с деньгами, в остальных случаях - не надо стрелять из пушки по воробьям.
В матлабе была такая же хрень. Когда работаешь с целыми всё норм. Как только дело касается вычислений с точкой начинались чудеса(ну для моего восприятия, с точки зрения машины делает что может).
Например должно получиться 12.2 , а получается неточность в последнем знаке например типа Double.
Там настраивается сколько знаков выводить при отображении но в любом случае показывают отклонение в последнем знаке. Например если настроить вывод коротких значений то выводит 12.200001 или 12.199999.
Приходилось предпринимать очень серьёзные усилия чтоб функции работали. При сравнениях например выходила лож хотя по коду я знал что должна быть истина. Приходилось запоминать отдельно целую часть, и отдельно дробную умноженную на 10 и округлённую до ближайшего целого, и учитывать всё это в коде функций.
Ну а что касается ситуации когда нужен результат при расчётах дробным числом, видимо придётся смириться с неточностями. Вы лиш можете выбрать самый оптимальный тип для конкретных расчётов.
Это и ежику понятно
То что числа с плавающей точкой имеют ограниченную точность - должно быть учтено в алгоритме.
Вам надо округлять до нужного значения или не ставить строгой проверки условия.
Согласитесь, что бывают и очень странные функции, значение которых может очень сильно отличаться даже при отклонении аргумента на одну миллионную. Возьмем чисто абстрактную функцию:
Double MyFunction(Double CurArg, Double PrevArg)
{
Double returnedValue;
//если текущий аргумент изменился на величину меньше 0.00001
if(Math.Abs(CurArg-PrevArg)<0.00001)
{
//вернем CurArg в 10 степени
returnedValue=Math.Pow(CurArg, 10);
}
//иначе
else
{
//вернем сумму CurArg и PrevArg в 100 степени
returnedValue=Math.Pow(CurArg+PrevArg,100);
}
return returnedValue;
}
Насчет того, что Decimal грузит процессор - думаю для каких-нибудь Core i7, всяких ядер из разряда AMD (Buldozer) это будет вполне простая задача. Еще соглашусь, что это неподъемная проблема для какого-нибудь Celeron 2000.
Спасибо за ответы, но это правда очень странно, всегда воспринимал Double как число двойной точности, а тут с элементарной операцией он справляется как-то странно