В iOS я обнаружил, что стандартные операторы тригонометрии имеют точность примерно до 13 или 14 десятичных цифр, поэтому звучит очень странно, что вы видите ошибки порядка 0,05 радиана. Если вы можете создать код и конкретные значения, демонстрирующие это, пожалуйста, подайте отчет об ошибке о поведении (и опубликуйте код здесь, чтобы мы могли получить его запись).
Тем не менее, если вам действительно нужна высокая точность для ваших операторов тригонометрии, я изменил несколько подпрограмм, которые Дейв Делонг создал для своего DDMathParser кода. Эти процедуры используют NSDecimal для выполнения математических операций, давая вам до ~ 34 цифр десятичной точности, избегая при этом ваших стандартных проблем с плавающей запятой при представлении десятичных десятичных чисел. Вы можете скачать код для этих измененных подпрограмм с здесь .
NSDecimal версия atan()
вычисляется с использованием следующего кода:
NSDecimal DDDecimalAtan(NSDecimal x) {
// from: http://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Infinite_series
// The normal infinite series diverges if x > 1
NSDecimal one = DDDecimalOne();
NSDecimal absX = DDDecimalAbsoluteValue(x);
NSDecimal z = x;
if (NSDecimalCompare(&one, &absX) == NSOrderedAscending)
{
// y = x / (1 + sqrt(1+x^2))
// Atan(x) = 2*Atan(y)
// From: http://www.mathkb.com/Uwe/Forum.aspx/math/14680/faster-Taylor-s-series-of-Atan-x
NSDecimal interiorOfRoot;
NSDecimalMultiply(&interiorOfRoot, &x, &x, NSRoundBankers);
NSDecimalAdd(&interiorOfRoot, &one, &interiorOfRoot, NSRoundBankers);
NSDecimal denominator = DDDecimalSqrt(interiorOfRoot);
NSDecimalAdd(&denominator, &one, &denominator, NSRoundBankers);
NSDecimal y;
NSDecimalDivide(&y, &x, &denominator, NSRoundBankers);
NSDecimalMultiply(&interiorOfRoot, &y, &y, NSRoundBankers);
NSDecimalAdd(&interiorOfRoot, &one, &interiorOfRoot, NSRoundBankers);
denominator = DDDecimalSqrt(interiorOfRoot);
NSDecimalAdd(&denominator, &one, &denominator, NSRoundBankers);
NSDecimal y2;
NSDecimalDivide(&y2, &y, &denominator, NSRoundBankers);
// NSDecimal two = DDDecimalTwo();
NSDecimal four = DDDecimalFromInteger(4);
NSDecimal firstArctangent = DDDecimalAtan(y2);
NSDecimalMultiply(&z, &four, &firstArctangent, NSRoundBankers);
}
else
{
BOOL shouldSubtract = YES;
for (NSInteger n = 3; n < 150; n += 2) {
NSDecimal numerator;
if (NSDecimalPower(&numerator, &x, n, NSRoundBankers) == NSCalculationUnderflow)
{
numerator = DDDecimalZero();
n = 150;
}
NSDecimal denominator = DDDecimalFromInteger(n);
NSDecimal term;
if (NSDecimalDivide(&term, &numerator, &denominator, NSRoundBankers) == NSCalculationUnderflow)
{
term = DDDecimalZero();
n = 150;
}
if (shouldSubtract) {
NSDecimalSubtract(&z, &z, &term, NSRoundBankers);
} else {
NSDecimalAdd(&z, &z, &term, NSRoundBankers);
}
shouldSubtract = !shouldSubtract;
}
}
return z;
}
При этом используется приближение ряда Тейлора с некоторыми ярлыками для ускорения сходимости. Я считаю, что точность не может быть полных 34 цифр при результатах, очень близких к пи / 4 радианам, поэтому мне, возможно, все же придется это исправить.
Если вам нужна предельная точность, это вариант, но опять же то, о чем вы сообщаете, не должно происходить со значениями double
, поэтому здесь есть что-то странное.