你在正确的轨道上(注意事项,见下文).您可以只使用NSNumber中的初始值设定项,因为它们是由NSDecimalNumber继承的.
NSDecimalNumber *floatDecimal = [[[NSDecimalNumber alloc] initWithFloat:42.13f] autorelease];
NSDecimalNumber *doubleDecimal = [[[NSDecimalNumber alloc] initWithDouble:53.1234] autorelease];
NSDecimalNumber *intDecimal = [[[NSDecimalNumber alloc] initWithInt:53] autorelease];
NSLog(@"floatDecimal floatValue=%6.3f", [floatDecimal floatValue]);
NSLog(@"doubleDecimal doubleValue=%6.3f", [doubleDecimal doubleValue]);
NSLog(@"intDecimal intValue=%d", [intDecimal intValue]);
关于这个主题的更多信息可以在here页上找到.
然而,我在网上看到了很多关于堆栈溢出的讨论,以及关于初始化NSDecimalNumber的问题.似乎存在一些与精确度以及与NSDecimalNumber
的双打之间的转换有关的问题.特别是当您使用从NSN成员处继承的号码时.
我完成了下面的测试:
double dbl = 36.76662445068359375000;
id xx1 = [NSDecimalNumber numberWithDouble: dbl]; // Don't do this
id xx2 = [[[NSDecimalNumber alloc] initWithDouble: dbl] autorelease];
id xx3 = [NSDecimalNumber decimalNumberWithString:@"36.76662445068359375000"];
id xx4 = [NSDecimalNumber decimalNumberWithMantissa:3676662445068359375L exponent:-17 isNegative:NO];
NSLog(@"raw doubleValue: %.20f, %.17f", dbl, dbl);
NSLog(@"xx1 doubleValue: %.20f, description: %@", [xx1 doubleValue], xx1);
NSLog(@"xx2 doubleValue: %.20f, description: %@", [xx2 doubleValue], xx2);
NSLog(@"xx3 doubleValue: %.20f, description: %@", [xx3 doubleValue], xx3);
NSLog(@"xx4 doubleValue: %.20f, description: %@", [xx4 doubleValue], xx4);
输出为:
raw doubleValue: 36.76662445068359375000 36.76662445068359375
xx1 doubleValue: 36.76662445068357953915, description: 36.76662445068359168
xx2 doubleValue: 36.76662445068357953915, description: 36.76662445068359168
xx3 doubleValue: 36.76662445068357953915, description: 36.76662445068359375
xx4 doubleValue: 36.76662445068357953915, description: 36.76662445068359375
因此,您可以看到,在NSNumber
(由于返回了错误的指针类型,您不应该真正使用)上使用numberWithDouble
便利方法,甚至在初始化器initWithDouble
(IMO"应该"可以调用)上使用numberWithDouble
便利方法时,您会得到一个NSDecimalNumber,其内部表示(通过调用对象上的description
返回)不如当你调用decimalNumberWithString:
或decimalNumberWithMantissa:exponent:isNegative:
时会得到一个.
另外,请注意,通过在NSDecimalNumber
实例上调用doubleValue
来转换回double会丢失精度,但有趣的是,无论调用哪个初始值设定器,转换都是一样的.
最后,我建议您在处理高精度浮点数时,使用NSDecimalNumber
类级别声明的decimalNumberWith*
个方法之一来创建NSDecimalNumber实例.
那么,当你有一个双精度、浮点数或其他数字时,如何轻松地调用这些初始值设定项呢?
两种方法描述了here个"工作",但仍然存在精度问题.
如果您已经将该号码存储为NSNumber,那么这should起作用:
id n = [NSNumber numberWithDouble:dbl];
id dn1 = [NSDecimalNumber decimalNumberWithDecimal:[n decimalValue]];
NSLog(@" n doubleValue: %.20f, description: %@", [n doubleValue], n);
NSLog(@"dn1 doubleValue: %.20f, description: %@", [dn1 doubleValue], dn1);
但正如您从下面的输出中看到的,它删除了一些不太重要的数字:
n doubleValue: 36.76662445068359375000, description: 36.76662445068359
dn1 doubleValue: 36.76662445068357953915, description: 36.76662445068359
如果数字是一个基本数(浮点或双精度),那么这should起作用:
id dn2 = [NSDecimalNumber decimalNumberWithMantissa:(dbl * pow(10, 17))
exponent:-17
isNegative:(dbl < 0 ? YES : NO)];
NSLog(@"dn2 doubleValue: %.20f, description: %@", [dn2 doubleValue], dn2);
但你会再次得到精度误差.正如您在下面的输出中所看到的:
dn2 doubleValue: 36.76662445068357953915, description: 36.76662445068359168
我认为这种精度损失的原因是由于涉及浮点乘法,因为以下代码工作正常:
id dn3 = [NSDecimalNumber decimalNumberWithMantissa:3676662445068359375L
exponent:-17
isNegative:NO];
NSLog(@"dn3 doubleValue: %.20f, description: %@", [dn3 doubleValue], dn3);
输出:
dn3 doubleValue: 36.76662445068357953915, description: 36.76662445068359375
因此,从double
或float
到NSDecimalNumber的最准确转换/初始化是使用decimalNumberWithString:
.但是,正如布拉德·拉森(Brad Larson)在回答中指出的那样,这可能有点慢.如果性能成为问题,他使用NSScanner进行转换的技术可能会更好.