Ios pow功能是如何工作的?

Ios pow功能是如何工作的?,ios,objective-c,c,Ios,Objective C,C,我想写我自己的幂函数来处理不是整数的小数和指数。我第一次尝试结合使用牛顿法和内置整数幂法,但由于牛顿法,当指数超过2位小数时,我会出现溢出错误。所以我想也许浮点值pow函数可以作为我自己函数的一个很好的模型。所以我想知道是否有人知道我在哪里可以找到一些关于pow函数内部工作原理的文档 编辑: @wombat57,这些链接看起来可能就是我要找的,但我不知道该怎么读。你建议的算法实际上就是我正在使用的。由于指数非常大,溢出来自牛顿方法。因为我得到的是十进制的指数,所以我必须先把它转换成分数。就我所知

我想写我自己的幂函数来处理不是整数的小数和指数。我第一次尝试结合使用牛顿法和内置整数幂法,但由于牛顿法,当指数超过2位小数时,我会出现溢出错误。所以我想也许浮点值pow函数可以作为我自己函数的一个很好的模型。所以我想知道是否有人知道我在哪里可以找到一些关于pow函数内部工作原理的文档

编辑:


@wombat57,这些链接看起来可能就是我要找的,但我不知道该怎么读。你建议的算法实际上就是我正在使用的。由于指数非常大,溢出来自牛顿方法。因为我得到的是十进制的指数,所以我必须先把它转换成分数。就我所知,在代码中,唯一的方法是将十进制数乘以10,直到得到一个整数,然后用它作为分子。这样,对于小数位数为3或更多的数字,指数为100+。这会导致溢出错误。

编辑1:以下是指向实际源的链接

我得到了这个问题的链接,这个问题有很多相关的讨论

此页面描述了一个算法:。 x^(1/n)=x的第n个根,x^mn=(x^m)^n。因此,x^(m/n)=(x的第n根)^m。可以用牛顿法计算任意根。整数幂可以通过平方求幂来计算。对于无理指数,可以使用越来越精确的有理近似,直到获得所需的有效位数

编辑2:

牛顿的方法包括将你目前的猜测提高到你试图找到的根的幂。如果该功率很大,并且猜测值甚至有点太高,则可能导致溢出。这里的一个解决方案是确定这种情况。如果发生溢出,这意味着猜测过高。您可以通过(每当猜测导致溢出时)将当前猜测设置为上一个没有溢出的猜测和当前猜测之间的值(您可能需要多次这样做)来解决此问题。也就是说,每当牛顿的方法溢出时,对没有溢出的最后一个猜测进行二进制搜索。下面是一些实现所有这些功能的python:

def nroot(n, b, sig_figs = 10):
    g1 = 1.0
    g2 = 1.0
    while True:
        done = False
        while not done:  
            try:
                g3 = g2 - ((g2**b) - n) / (b * (g2**(b-1)))
                done = True
            except OverflowError:
                g2 = (g1 + g2) / 2.0 

        if abs(g2 - g3) < 1.0 / (10**sig_figs):
            return g3
        g1 = g2
        g2 = g3

def npowbysqr(n, p):
    if p == 0:
        return 1.0
    if p % 2 == 0:
        v = npowbysqr(n, p/2)
        return v*v 
    else:
        return n*npowbysqr(n, p-1)

def npow(n, p):
    return npowbysqr(nroot(n, 1000000), int(p*1000000))

print npow(5, 4.3467)
print 5**4.3467   
def nroot(n,b,sig_图=10):
g1=1.0
g2=1.0
尽管如此:
完成=错误
虽然没有这样做:
尝试:
g3=g2-((g2**b)-n)/(b*(g2**(b-1)))
完成=正确
除溢出错误外:
g2=(g1+g2)/2.0
如果abs(g2-g3)<1.0/(10**sig_图):
返回g3
g1=g2
g2=g3
def npowbysqr(n,p):
如果p==0:
返回1.0
如果p%2==0:
v=npowbysqr(n,p/2)
返回v*v
其他:
返回n*npowbysqr(n,p-1)
def npow(n,p):
返回npowbysqr(nroot(n,1000000),int(p*1000000))
打印npow(5,4.3467)
打印5**4.3467

我应该补充一点,也许有更好的解决办法。这似乎是可行的,但是不久前我碰巧需要这样的东西。谢天谢地,戴夫·德隆在他的DDMathParser中一直在修补这一点,所以我就以此为基础进行了构建。他从他的代码中删除了他的实现,但我接受了并修改了它。这是我对他的十进制幂函数的理解:

extern NSDecimal DDDecimalPower(NSDecimal d, NSDecimal power) {
    NSDecimal r = DDDecimalOne();
    NSDecimal zero = DDDecimalZero();
    NSComparisonResult compareToZero = NSDecimalCompare(&zero, &power);
    if (compareToZero == NSOrderedSame) {
        return r;
    }
    if (DDDecimalIsInteger(power))
    {
        if (compareToZero == NSOrderedAscending)
        {
            // we can only use the NSDecimal function for positive integers
            NSUInteger p = DDUIntegerFromDecimal(power);
            NSDecimalPower(&r, &d, p, NSRoundBankers);
        }
        else
        {
            // For negative integers, we can take the inverse of the positive root
            NSUInteger p = DDUIntegerFromDecimal(power);
            p = -p;
            NSDecimalPower(&r, &d, p, NSRoundBankers);
            r = DDDecimalInverse(r);
        }
    } else {
        // Check whether this is the inverse of an integer        
        NSDecimal inversePower = DDDecimalInverse(power);
        NSDecimalRound(&inversePower, &inversePower, 34, NSRoundBankers); // Round to 34 digits to deal with cases like 1/3

        if (DDDecimalIsInteger(inversePower))
        {
            r = DDDecimalNthRoot(d, inversePower);
        }
        else
        {
            double base = DDDoubleFromDecimal(d);
            double p = DDDoubleFromDecimal(power);
            double result = pow(base, p);
            r = DDDecimalFromDouble(result);
        }        
    }
    return r;
}
它试图找出常见的情况,并对这些情况进行更精确的计算。但是,对于不适合这些情况的事情,它确实依赖于pow()


我使用的其余NSDecimal函数都可以找到和找到。

我已经找到了一个适合我需要的函数,并且有望满足许多其他人的需要。以下方法是完全注释的,适用于任何具有实值的幂函数。此方法还仅使用NSDEcimalNumber,这意味着您不会因为浮点舍入错误而失去任何精度。这个方法有两个参数,一个是基数,一个是幂,都是小数。这就是:

//these are constants that will be used
NSDecimalNumber *ten = [NSDecimalNumber decimalNumberWithString:@"10"];
NSDecimalNumber *one = NSDecimalNumber.one;

//these will together hold the power in fractional form
NSDecimalNumber *numerator = power, *denominator = one;

//this will hold the final answer and all previous guesses the first guess is set to be the base
NSDecimalNumber *powAns = base;

//this will hold the change in your guess, also serves as an idea of how large the error is
NSDecimalNumber *error = one;

//part1 holds f(x) and part2 holds f'(x)
NSDecimalNumber *part1, *part2;

//if the base is < 0 and the power is not whole, answer is not real
if ([base doubleValue] < 0 && [[power stringValue] rangeOfString:@"."].location != NSNotFound)
    return NSDecimalNumber.notANumber;

//converts power to a fractional value
while ([[numerator stringValue] rangeOfString:@"."].location != NSNotFound) {

    numerator = [numerator decimalNumberByMultiplyingBy:ten];
    denominator = [denominator decimalNumberByMultiplyingBy:ten];
}

//conditions here are the precision you wish to get
while ([error compare:[NSDecimalNumber decimalNumberWithString:@"1e-20"]] == NSOrderedDescending ||
       [error compare:[NSDecimalNumber decimalNumberWithString:@"-1e-20"]] == NSOrderedAscending) {

    //if this catches an overflow error it is set to be a very large number otherwise the value cannot be a number, however no other error should be returned.
    @try {
        part1 = [powAns decimalNumberByRaisingToPower:[denominator intValue]];
    }
    @catch (NSException *exception) {

        if ([exception.name isEqual: NSDecimalNumberOverflowException])
            part1 = [NSDecimalNumber decimalNumberWithString:@"10e127"];

        else
            return NSDecimalNumber.notANumber;
    }

    part1 = [part1 decimalNumberBySubtracting:base];

    //if this catches an overflow error it is set to be a very large number otherwise the value cannot be a number, however no other error should be returned.
    @try {
        part2 = [powAns decimalNumberByRaisingToPower:[denominator intValue]-1];
        part2 = [part2 decimalNumberByMultiplyingBy:denominator];
    }
    @catch (NSException *exception) {

        if ([exception.name isEqual: NSDecimalNumberOverflowException])
            part2 = [NSDecimalNumber decimalNumberWithString:@"10e127"];

        else
            return NSDecimalNumber.notANumber;
    }

    //error is the change in the estimated value or y - f(x)/f'(x)
    error = [part1 decimalNumberByDividingBy:part2];
    powAns = [powAns decimalNumberBySubtracting: error];
}

//if the numerator value is negative it must be made positive and the answer is then inverted
if ([numerator intValue] < 0) {
    powAns = [powAns decimalNumberByRaisingToPower:abs([numerator intValue])];
    powAns = [one decimalNumberByDividingBy:powAns];
}
else
    powAns = [powAns decimalNumberByRaisingToPower:[numerator intValue]];

return powAns;
//这些是将要使用的常量
NSDecimalNumber*ten=[NSDecimalNumber decimalnumberwhithstring:@“10”];
NSDecimalNumber*one=NSDecimalNumber.one;
//这些将以分数形式共同持有权力
N小数*分子=幂,*分母=一;
//这将保留最终答案和之前的所有猜测-第一个猜测被设置为基础
NSDecimalNumber*powAns=基数;
//这将保持你猜测的变化,也可以作为误差有多大的概念
NSDecimalNumber*错误=1;
//第1部分保持f(x),第2部分保持f'(x)
N小数*第1部分,*第2部分;
//如果基数<0且功率不完整,则答案不真实
如果([base doubleValue]<0&&[power stringValue]rangeOfString:@“)。位置!=NSNotFound)
返回NSDecimalNumber.notANumber;
//将幂转换为小数
while([[numerator stringValue]rangeOfString:@.”).location!=NSNotFound){
分子=[分子小数位数乘:十];
分母=[分母小数位数乘:十];
}
//这里的条件是您希望获得的精度
而([错误比较:[NSDecimalNumber decimalNumberWithString:@“1e-20”]]==取消搜索||
[错误比较:[NSDecimalNumber decimalNumberWithString:@“-1e-20”]==传感器解除设置){
//如果捕获到溢出错误,则将其设置为非常大的数字,否则该值不能为数字,但不应返回其他错误。
@试一试{
第1部分=[powAns decimalNumberByRaisingToPower:[分母intValue]];
}
@捕获(NSException*异常){
if([exception.name isEqual:NSDecimalNumberOverflowException])
第1部分=[NSDecimalNumber decimalNumberWithString:@“10e127”];
其他的
返回NSDecimalNumber.notANumber;
}
part1=[part1小数位数