我使用 NSNumber 来存储各种值,但有时在使用值进行计算并为结果初始化新的 NSNumber 对象时会遇到问题。我已经想出了如何克服它,但我无法终生解释它为什么会起作用,而且由于我对计算机环境中的数值(双精度数、浮点数等)的把握很弱,所以我想问这个要学习的问题。:-)
第一个例子是当我在不同的测量单位之间进行转换时,在这种特殊情况下,它在 mmol/L 和 mg/dl 之间。得到一个代表 mmol/L 值的 NSNumber,我提取它的 double 值并执行计算。然后我用 -initWithDouble 创建一个新的 NSNumber 并返回结果。
但是,我有奇怪的怪癖。如果 mmol/L 值为 10.0,则对应的 mg/dl 值为 180.0(显然,比率仅为 18)。但是当我稍后需要让用户在选择器视图中选择一个新值并使用 NSNumber -intValue 来获取当前值的整数位时(使用我自己的扩展来获取小数位),int 是 179!我在计算过程中检查了所有中间双精度值以及新 NSNumber 的双精度值,一切都很好(结果是 180.00000)。有趣的是,并非所有值都会发生这种情况,只有一些值(10.0 是一个真实的例子)。
第二个示例是当我从 Sqlite3 数据库中检索双精度值并将它们存储在 NSNumbers 中时。同样,大多数值都可以正常工作,但偶尔我会得到一些奇怪的东西。例如,如果我在数据库中保存 6.7(检查它何时保存,这实际上是值),检索后我的 NSNumber 将显示为 6.699999。(在撰写本文时,我实际上不记得这是否也是数据库中的内容,但我认为是 - 我可以稍后再检查。)
这两个实例都可以通过使用中间浮点值和 NSNumber initWithFloat 而不是 initWithDouble 来规避。因此,例如,在我的转换中,我只是做了一个 float resultAsFloat = resultAsDouble 并将 initWithFloat 用于新的 NSNumber。
为这个冗长的问题道歉,如果这只是我自己对处理数值的知识所缺乏的,但如果有人能向我解释这一点,我将不胜感激!
谢谢,
安德斯
* 编辑 1 *
单位转换示例的代码:
-(NSNumber *)convertNumber:(NSNumber *)aNumber withUnit:(FCUnit *)aUnit {
// if origin unit and target unit are the same, return original number
if ([aUnit.uid isEqualToString:self.target.uid])
return aNumber;
// determine if origin unit and target unit are comparable
if (aUnit.quantity != self.target.quantity)
return nil;
// if so, convert the number...
// get bases
double originBase;
double targetBase;
if (aUnit.metre != nil) {
originBase = [aUnit.metre doubleValue];
targetBase = [self.target.metre doubleValue];
} else if (aUnit.kilogram != nil) {
originBase = [aUnit.kilogram doubleValue];
targetBase = [self.target.kilogram doubleValue];
} else if (aUnit.second != nil) {
originBase = [aUnit.second doubleValue];
targetBase = [self.target.second doubleValue];
} else if (aUnit.quantity == FCUnitQuantityGlucose) {
// special case for glucose
if ([aUnit.uid isEqualToString:FCKeyUIDGlucoseMillimolesPerLitre]) { // mmol/L -> mg/dl
originBase = 1;
targetBase = 0.0555555555555556; // since 1 / 0.0555555555555556 = 18
} else if ([aUnit.uid isEqualToString:FCKeyUIDGlucoseMilligramsPerDecilitre]) { // mg/dl -> mmol/L
originBase = 0.0555555555555556;
targetBase = 1;
}
}
// find conversion rate
double rate = originBase / targetBase;
// convert the value
double convert = [aNumber doubleValue] * rate;
// TMP FIX: this fixes an issue where the intValue of convertedNumber would be one less
// than it should be if the number was created with a double instead of a float. I have
// no clue as to why...
float convertAsFloat = convert;
// create new number object and return it
NSNumber *convertedNumber = [[NSNumber alloc] initWithFloat:convertAsFloat];
[convertedNumber autorelease];
return convertedNumber;
}