NSNumber -initWithDouble问题和结果值

时间:2010-09-16 15:28:21

标签: iphone objective-c floating-point double nsnumber

我正在使用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数据库中检索double值并将它们存储在NSNumbers中时。同样,大多数价值观都很好,但偶尔我会得到奇怪的东西。例如,如果我在数据库中保存6.7(检查它何时被保存,实际上是值),我的NSNumber在检索后将显示的是6.699999。 (我现在实际上还记不起写作的那一刻,如果这也是数据库中的内容,但我认为是 - 我可以稍后再查看。)

这两个实例都可以通过使用中间浮点值和NSNumber initWithFloat而不是initWithDouble来规避。所以在我的转换中,例如,我只是执行一个float resultAsFloat = resultAsDouble并使用initWithFloat作为新的NSNumber。

为冗长的问题道歉,如果只是我自己对使用缺乏数值的知识,但如果有人能向我解释,我真的很感激!

谢谢,

的Anders

*编辑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;
}

2 个答案:

答案 0 :(得分:2)

尝试使用NSDecimalNumber。这里有一个很好的教程:

http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/

答案 1 :(得分:0)

如果我没有错,如果我记得在大学里适当的课程,我认为这是从现实(你有无限的价值观)转变为虚拟的问题(即使你有很多,你也有有限的价值) :所以你实际上不能代表所有数字。你还必须面对你正在进行的操作:乘法和除法会产生很多这样的麻烦,因为你会有很多十进制数,而且在我看来,基于C语言不是最好的管理这个有点事。 希望这会为您提供更好的信息来源:)。