且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-25 18:44:51

不幸的是,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所获得的精度,并且会使自己遇到浮点错误。



Core Plot框架中采用的方法:
  NSDecimal CPDecimalFromString(NSString * stringRepresentation)
{
NSDecimal result;
NSScanner * theScanner = [[NSScanner alloc] initWithString:stringRepresentation];
[theScanner scanDecimal:& result];
[theScanner release];

返回结果;
}

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


I am carrying out a number of calculations using NSDecimal and am creating each NSDecimal struct using the following technique:

[[NSNumber numberWithFloat:kFloatConstant] decimalValue]

I am using NSDecimal to avoid using autoreleased NSDecimalNumber objects (if the NSDecimalNumber approach to accurate calculations is used). However it seems that the NSNumber creation mechanism also returns an autoreleased NSNumber from which the decimal value is extracted.

Is there a way to create an NSDecimal without using NSNumber and creating autoreleased objects?

Unfortunately, Apple does not provide any easy ways of putting values into an NSDecimal struct. The struct definition itself can be found in the NSDecimal.h header:

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;

but I don't know that I would go around trying to reverse-engineer how the structs hold values. The underscores on the fields in the struct indicate that these are private and subject to change. I don't imagine that a lot of changes occur in the low-level NSDecimal functions, but I'd be nervous about things breaking at some point.

Given that, initializing an NSDecimal from a floating point number is best done in the way that you describe. However, be aware that any time you use a floating point value you are losing the precision you've gained by using an NSDecimal, and will be subjecting yourself to floating point errors.

I always work only with NSDecimals within my high-precision calculations, and take in and export NSStrings for exchanging these values with the outside world. To create an NSDecimal based on an NSString, you can use the approach we take in the Core Plot framework:

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

    return result;
}

Using an NSScanner instead of NSDecimalNumber -initWithString:locale: is about 90% faster in my benchmarks.