0

私は NSNumber を使用してさまざまな値を保存していますが、値を使用して計算を行い、結果の新しい NSNumber オブジェクトを初期化するときに問題が発生することがあります。私はそれを克服する方法を考え出しましたが、なぜそれが機能するのかを一生説明することはできませんでした。また、コンピューター環境(double、floatなど)での数値の理解が弱いため、これを尋ねたいと思います学ぶ質問。:-)

最初の例は、異なる測定単位間で変換する場合です。この特定のケースでは、mmol/L と mg/dl の間です。mmol/L 値を表す NSNumber を取得し、その double 値を抽出して計算を実行します。次に、-initWithDouble を使用して新しい NSNumber を作成し、結果を返します。

しかし、私は奇妙なクセを取得します。mmol/L 値が 10.0 の場合、対応する mg/dl 値は 180.0 です (速度は、明らかに単純に 18 です)。しかし、後でユーザーがピッカー ビューで新しい値を選択できるようにし、NSNumber -intValue を使用して現在の値の整数桁を取得する必要がある場合 (小数桁を取得するために独自の拡張機能を使用)、int は 179 です! 計算中にすべての中間 double 値と新しい NSNumber の double 値を確認しましたが、すべて問題ありません (結果は 180.00000 です)。興味深いことに、これはすべての値で発生するわけではなく、一部の値で発生します (10.0 が実際の例です)。

2 番目の例は、Sqlite3 データベースから double 値を取得し、それらを NSNumbers に格納する場合です。繰り返しますが、ほとんどの値は正常に機能しますが、時々奇妙なものが返されます。たとえば、データベースに 6.7 を保存すると (保存時に実際の値であることを確認します)、取得後に NSNumber に表示されるのは 6.699999 です。(これを書いている時点では、それがデータベースにもあるのかどうかは実際には思い出せませんが、そうだと思います - 後で確認できます。)

これらのインスタンスは両方とも、initWithDouble の代わりに中間の float 値と NSNumber initWithFloat を使用することで回避できます。たとえば、私の変換では、float resultAsFloat = resultAsDouble を実行し、新しい NSNumber に initWithFloat を使用します。

長々とした質問で申し訳ありません。また、数値の操作に関する私自身の知識が不足している場合は、申し訳ありませんが、誰かがこれを説明していただければ幸いです。

ありがとう、

アンダース

*編集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;
}
4

2 に答える 2

2

NSDecimalNumber を使用してみてください。ここに良いチュートリアルがあります:

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

于 2010-09-16T16:10:18.883 に答える
0

私が間違っていなくて、大学での適切なコースをよく覚えていれば、それは現実 (無限の価値がある場所) から仮想 (多くの価値があっても有限の価値がある場所) への変換の問題だと思います。実際にはすべての数値を表すことはできません。また、実行中の演算にも直面する必要があります。掛け算と割り算は、この問題の多くを生成します。これは、多くの 10 進数があるためです。私の意見では、C ベースの言語はこれを管理するのに最適ではありません。種類の問題。これがより良い情報源を示してくれることを願っています:)。

于 2010-11-05T16:38:07.810 に答える