【问题标题】:NSDecimalNumber to the power of NSDecimalNumberNSDecimalNumber 的 NSDecimalNumber 次幂
【发布时间】:2012-08-23 14:32:01
【问题描述】:

我有两个 NSDecimalNumbers,我需要将一个应用到另一个的幂,最初这段代码使用双精度数,我可以使用 pow() 函数计算它,如下所示:

double result = pow(value1, value2);

我遇到的问题是我将代码转换为使用 NSDecimalNumbers,虽然它们包含 toThePowerOf 方法,但它只接受 int 值。目前我必须解决这个问题的唯一方法是临时转换 NSDecimalNumbers 但这会导致精度损失。

double value1 = [decimal1 doubleValue];
double value2 = [decimal2 doubleValue];

double result = pow(value1, value2);
NSDecimalNumber *decimalResult = [[NSDecimalNumber alloc] initWithDouble:result];

有没有一种方法可以让我使用 NSDecimalNumbers 进行此计算而不会丢失精度?

我需要它来处理非整数值,例如:

value1 = 1.06
value2 = 0.0277777777

【问题讨论】:

  • value2 的范围有什么限制吗?

标签: objective-c ios xcode math nsdecimalnumber


【解决方案1】:

正如 Joe 所指出的,如果您想对正整数幂执行此操作,您可以在派生自 NSDecimalNumber 的 NSDecimal 结构上使用 NSDecimalPower()(我个人更喜欢使用这些结构,因为 performance reasons)。

对于使用负整数和小数值的更一般情况,我有一些从 Dave DeLong 的 DDMathParser 库中修改的代码。他已经删除了这个库的 NSDecimal 部分,但你可以找到the last commit for this support。我将 Dave 的指数支持扩展到以下函数:

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;
}

这将对直接映射到根的正整数幂、负整数幂和分数幂进行精确计算。不过,它仍然依赖浮点计算来计算没有完全落入其中一个箱的分数幂。

不幸的是,这需要他的一些其他支持功能才能发挥作用。因此,我上传了提供此功能的他的_DDDecimalFunctions.h_DDDecimalFunctions.m 的增强版本。它们还包括 NSDecimal 三角函数、对数和其他一些函数。目前在切线实现上存在一些收敛问题,这就是为什么我还没有完成关于此的公开帖子。

【讨论】:

  • 所以如果它是分数,这使用 pow 吗?我遇到的问题是我不想使用 pow 并且我知道我的数字将是实数。抱歉,我可能在开始的问题中对此并不了解。
  • @RobGill - 对于偶数分数(1/3、1/4),它能够将它们简化为精确的根并保持精度。 pow() 是不映射到根或逆的情况的后备,例如 2^(1.05)。我不知道比这更精确的指数的任何其他 NSDecimal / NSDecimalNumber 实现,这就是为什么我构建了 Dave 的初始实现。如果你能找到这样的功能,请告诉我,因为我可以自己使用。
【解决方案2】:

我最近遇到了同样的问题,并开发了自己的函数来解决这个问题。函数 has 将计算任何基数,只要它产生一个真正的答案,如果它确定一个真正的答案不能被计算它返回NSDecimalnumber.notANumber

我已经发布了我的解决方案,作为对我发布的同一问题的答案,所以here 是链接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多