【问题标题】:Is there a way to create an NSDecimal without using NSNumber and creating autoreleased objects?有没有办法在不使用 NSNumber 和创建自动释放对象的情况下创建 NSDecimal?
【发布时间】:2011-01-03 08:57:35
【问题描述】:

我正在使用 NSDecimal 进行一些计算,并使用以下技术创建每个 NSDecimal 结构:

[[NSNumber numberWithFloat:kFloatConstant] decimalValue]

我使用NSDecimal 来避免使用自动释放的NSDecimalNumber 对象(如果使用NSDecimalNumber 方法进行精确计算)。然而,NSNumber 创建机制似乎也返回了一个自动释放的NSNumber,从中提取了十进制值。

有没有办法在不使用 NSNumber 和创建自动释放对象的情况下创建 NSDecimal

【问题讨论】:

  • 看起来NSDecimal 确实是为具有特定精度范围的事物而设计的> floatdouble,因为存在丢失精度的风险。您能告诉我们更多关于您的用例的信息吗?

标签: ios objective-c autorelease


【解决方案1】:

不幸的是,Apple 没有提供将值放入 NSDecimal 结构的任何简单方法。结构定义本身可以在 NSDecimal.h 头文件中找到:

typedef struct {
    signed   int _exponent:8;
    unsigned int _length:4;     // length == 0 && isNegative -> NaN
    unsigned int _isNegative:1;
    unsigned int _isCompact:1;
    unsigned int _reserved:18;
    unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;

但我不知道我会四处尝试对结构如何保存值进行逆向工程。结构中字段上的下划线表示这些是私有的并且可能会更改。我不认为低级 NSDecimal 函数会发生很多变化,但我会担心在某些时候会出现问题。

鉴于此,最好按照您描述的方式从浮点数初始化 NSDecimal。但是,请注意,任何时候使用浮点值都会失去使用 NSDecimal 获得的精度,并且会导致浮点错误。

在我的高精度计算中,我总是只使用 NSDecimals,并接收和导出 NSStrings 以与外界交换这些值。要基于 NSString 创建 NSDecimal,可以使用我们在 Core Plot framework 中采用的方法:

NSDecimal CPDecimalFromString(NSString *stringRepresentation)
{
    NSDecimal result;
    NSScanner *theScanner = [[NSScanner alloc] initWithString:stringRepresentation];
    [theScanner scanDecimal:&result];
    [theScanner release];

    return result;
}

在我的基准测试中,使用 NSScanner 而不是 NSDecimalNumber -initWithString:locale: 大约快 90%。

【讨论】:

  • NSDecimal 类被误解了,这是因为它违反直觉。为什么苹果让它对程序员不友好? NSDecimal 的替代品有哪些?
  • @AndrewS - 一方面, NSDecimal 不是一个类,而是一个结构体,因此它的处理方式需要与标准对象稍有不同。 NSDecimal 处理函数的复杂性似乎源于希望使它们尽可能快。请注意,它们通过引用传递给这些函数,这只是一种优化。不过,没有任何借口可以为 NSDecimals 提供一个简单的构造函数。
  • 还有像NSInteger这样更原始的小数吗?
  • 除非一个字符串以字符串开头,否则我会避免为了将一种数字类型 (float) 转换为另一种 (NSDecimal) 而往返。
【解决方案2】:

要回答 “没有自动释放对象” 部分,只需:

NSDecimalNumber *intermediateNumber = [[NSDecimalNumber alloc] initWithFloat:kFloatConstant];
NSDecimal decimal = [intermediateNumber decimalValue];
[intermediateNumber release];

【讨论】:

  • 这里的问题不在于对象是自动释放的,而是从一开始就避免分配它。 NSDecimalNumber 的任何分配,无论是否自动释放,都将比处理 NSDecimal 结构:stackoverflow.com/questions/1704504/… 慢。这些对象的创建和销毁有很大的开销。您还假设它们以浮点值开头,希望在处理 NSDecimals 和 NSDecimalNumbers 时不会出现这种情况。
  • 另外,您可能不想使用 -initWithFloat: 原因如下:stackoverflow.com/a/5304993/19679
  • @BradLarson 这就是为什么我在答案前加上“回答‘没有自动释放对象’部分”。
  • @BradLarson initWithFloat: 用于匹配问题中的 numberWithFloat:kFloatConstant。很明显,OP 是从浮点数开始的。
  • @BradLarson 阅读不准确的问题;对我来说听起来像是 NSNumber/NSDecimalNumber 的实现中的一个错误。正如我上面所说的,如果准确度对您很重要,请不要使用 NSDecimal/NSDecimalNumber。
猜你喜欢
  • 1970-01-01
  • 2011-01-15
  • 2016-07-07
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多