将 NSString 转换为 NSNumber 会导致数字过多和奇怪的舍入
Posted
技术标签:
【中文标题】将 NSString 转换为 NSNumber 会导致数字过多和奇怪的舍入【英文标题】:Converting NSString to NSNumber results in too many digits and strange rounding 【发布时间】:2012-07-03 17:44:17 【问题描述】:在将包含两位标准十进制数字(例如 8.20)的 NSString
转换为 NSNumber
时,当通过 @987654323 记录结果时,我(不时)得到额外的数字和奇怪的舍入行为@ 或将其保存在 Core Data 中(作为浮点数或双精度数),例如8.20 -> 8.199999999999999。
这是我用来转换数字的代码:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:5];
NSNumber *num = [numberFormatter numberFromString:str];
我不明白为什么转换为 NSNumber 会弄乱数字。我的代码有什么问题?
【问题讨论】:
请教授解释“浮点数”。 【参考方案1】:这就是 float 和 double 在 C/Objective-C(以及许多其他语言)中的行为方式。例如,当您输入 python 8.0 时,结果将是 8.000000000001。我建议使用NSScanner 将它们转换为原始数字类型(double、float)。
【讨论】:
但是如果Core Data存储的是8.00000001而不是8.0会正确吗? 换一种说法 - 双精度浮点数无法准确表示最常见的分数。您只知道输入的数字 - 您输出的数字应该精确到大约 10^15 的一部分。 正确。这就是为什么不建议使用 == 比较两个浮点数/双精度数的原因。 (float1 == float2
不好。Abs(float1 - float2) <= epsilon
好。)
@AlexR:如果您想了解为什么这是正确的行为,请参阅docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html。如果你不想读那句话,那就接受它是真的。
感谢大家澄清这一点。你很有帮助。由于我处理的数据主要是货币数据,所以我现在使用 NSDecimalNumber 而不是 float 和 double。你对 NSDecimalNumber 有什么看法?【参考方案2】:
为什么要使用 NSNumberFormatter 将字符串转换为浮点数,这将是一个矫枉过正, 要转换它,只需使用
NSNumber *num = [NSNumber numberWithFloat:[str floatValue]];
【讨论】:
【参考方案3】:我在使用 NSNumber 保存双值时遇到了问题 8.28 总是显示 8.2799999999 ......,我猜它是由计算机数值精度引起的 试试这个代码。
+ (NSString *)dealWithDouble:(double)doubleValue
double d2 = doubleValue;
NSString *d2Str = [NSString stringWithFormat:@"%lf", d2];
NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithString:d2Str];
NSString *str2D = [num stringValue];
return str2D;
【讨论】:
【参考方案4】:不要使用浮点值。 floatValue 仅提供 24 位精度。 doubleValue 给出 53 位精度。例如,如果您使用超过一百万美元的数字,floatValue 无法为您提供任何相差小于 6 美分的值。 (1,000,000 美元,然后是 1,000,000.06 美元等)
规则是:除非你知道你应该使用float而不是double的原因,否则不要使用float。
【讨论】:
使用双精度计算货币也是非常错误和愚蠢的。fixed
精度必须用于货币。
如果您知道自己在做什么并避免迷信,使用 double 进行货币计算绝对没问题。以上是关于将 NSString 转换为 NSNumber 会导致数字过多和奇怪的舍入的主要内容,如果未能解决你的问题,请参考以下文章
将 NSString 转换为特定于语言环境的 NSNumber
在 CoreData 实体中将属性从 NSNumber 转换为 NSString - LightWeightMigration