oc精度计算

floata =0.01;intb =99999999;doublec =0.0;c = a*b;NSLog(@"%f",c);//输出结果为 1000000.000000NSLog(@"%.2f",c);//输出结果为 1000000.00//明显不够精确

在网上找到了一个国内朋友的博客也遇到和我一样的问题,他尝试了如下两种解决方案

将float强制转换为double

c= a*(double)b;NSLog(@"%f",c);//输出结果  999999.967648NSLog(@"%.2f",c);//输出结果  999999.97// 明显已经丢失精度

通过和NSString的转换,将计算的原始数据转换为纯粹的double类型的数据,这样的计算精度就可以达到要求了

NSString*objA = [NSStringstringWithFormat:@"%.2f", a];NSString*objB = [NSStringstringWithFormat:@"%.2f", (double)b];c = [objA doubleValue] * [objB doubleValue];NSLog(@"%.2f",c);//输出结果  999999.99

最终方案

NSString*decimalNumberMutiplyWithString(NSString*multiplierValue,NSString*multiplicandValue){NSDecimalNumber*multiplierNumber = [NSDecimalNumberdecimalNumberWithString:multiplierValue];NSDecimalNumber*multiplicandNumber = [NSDecimalNumberdecimalNumberWithString:multiplicandValue];NSDecimalNumber*product = [multiplicandNumber decimalNumberByMultiplyingBy:multiplierNumber];return[product stringValue];}NSLog(@"%@",decimalNumberMutiplyWithString([NSStringstringWithFormat:@"%f",a], [NSStringstringWithFormat:@"%d",b]));//输出结果  999999.99

下面开始讲解这个NSDecimalNumber

The NSDecimalNumber class provides fixed-point arithmetic算法capabilities功能to Objective-C programs. They’re designed to perform base-10 calculations without loss of precision精度and with predictable可预测的rounding凑整behavior. This makes it a better choice for representing表示currency货币than floating-point data types like double. However, the trade-off is that they are more complicated to work with.

NSDecimalNumber这个类为OC程序提供了定点算法功能,它被设计为了不会损失精度并且可预先设置凑整规则的10进制计算,这让它成为一个比浮点数(double)更好的选则去表示货币,然而作为交换用NSDecimalNumber计算变得更加复杂

Internally, a fixed-point number is expressed as表示为sign符号mantissa尾数x 10^exponent指数. The sign defines whether it’s positive or negative, the mantissa is an unsigned integer representing the significant有意义的digits有效数字, and the exponent determines where the decimal小数point falls in the mantissa.

在内部,一个有小数点的数被表示为上图中的这种形式,这个符号定义了它是正数还是负数,这个尾数是一个无符号的整数用来表示有效数字,这个指数决定了小数点在尾数中的位置

It’s possible to对...是可能的manually手动地assemble装配an NSDecimalNumber from a mantissa, exponent, and sign, but it’s often easier to convert it from a string representation表示. The following snippet片段creates the value 15.99 using both methods.

NSDecimalNumber*price;    price = [NSDecimalNumberdecimalNumberWithMantissa:1599exponent:-2isNegative:NO];    price = [NSDecimalNumberdecimalNumberWithString:@"15.99"];

对手动地用尾数,指数,符号来装配一个NSDecimalNumber是可能的,但是但是从一个字符串表示转换成一个NSDecimalNumber更容易,以下的片段创建了值15.99用两个方法

Like NSNumber, all NSDecimalNumber objects are immutable不可变的, which means you cannot change their value after they’ve been created.

像NSNumber一样,所有的NSDecimalNumber对象都是不可变额,这意味着在它们创建之后不能改变它们的值

Arithmetic算法

The main job of NSDecimalNumber is to provide fixed-point alternatives可供选择的事物to C’s native原生arithmetic operations操作. All five of NSDecimalNumber’s arithmetic methods are demonstrated演示below在...下.

NSDecimalNumber的主要工作是提供可供选择的定点算法给C的原生算法操作,全部的五个NSDecimalNumber的计算方法在下面被演示

NSDecimalNumber*price1 = [NSDecimalNumberdecimalNumberWithString:@"15.99"];NSDecimalNumber*price2 = [NSDecimalNumberdecimalNumberWithString:@"29.99"];NSDecimalNumber*coupon = [NSDecimalNumberdecimalNumberWithString:@"5.00"];NSDecimalNumber*discount = [NSDecimalNumberdecimalNumberWithString:@".90"];NSDecimalNumber*numProducts = [NSDecimalNumberdecimalNumberWithString:@"2.0"];NSDecimalNumber*subtotal = [price1 decimalNumberByAdding:price2];NSDecimalNumber*afterCoupon = [subtotal decimalNumberBySubtracting:coupon];NSDecimalNumber*afterDiscount = [afterCoupon decimalNumberByMultiplyingBy:discount];NSDecimalNumber*average = [afterDiscount decimalNumberByDividingBy:numProducts];NSDecimalNumber*averageSquared = [average decimalNumberByRaisingToPower:2];NSLog(@"Subtotal: %@", subtotal);// 45.98NSLog(@"After coupon: %@", afterCoupon);// 40.98NSLog((@"After discount: %@"), afterDiscount);// 36.882NSLog(@"Average price per product: %@", average);// 18.441NSLog(@"Average price squared: %@", averageSquared);// 340.070481

Unlike their floating-point counterparts相对物, these operations are guaranteed保证to be accurate精确. However, you’ll notice that many of the above calculations result in extra decimal places. Depending on the application, this may or may not be desirable (e.g., you might want to constrain约束currency values to 2 decimal places). This is where custom rounding凑整behavior comes in.

不像它们的相对物浮点,这些操作保证了精确性,然而,你会注意到有很多超出计算结果的额外小数位,根据这个应用,它们可能会也可能不会令人满意(例如,你可能想约束货币值只有2个小数位),这是为什么自定义进位行为被引入的原因

Rounding Behavior

// Rounding policies :// Original// value    1.2  1.21  1.25  1.35  1.27// Plain    1.2  1.2  1.3  1.4  1.3// Down    1.2  1.2  1.2  1.3  1.2// Up      1.2  1.3  1.3  1.4  1.3// Bankers  1.2  1.2  1.2  1.4  1.3

Each of the above arithmetic methods have an alternate替换物withBehavior: form that let you define how the operation rounds the resulting value. The NSDecimalNumberHandler class encapsulates封装a particular多有的,特别的rounding behavior and can be instantiated as follows:

每一个在上文中的计算方法有一个替换物---behavior:下面列出了让你定义这个操作凑整这个结果的值,这个类封装了一个特别的凑整行为,可以被实例化如下:

NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandlerdecimalNumberHandlerWithRoundingMode:NSRoundUpscale:2raiseOnExactness:NOraiseOnOverflow:NOraiseOnUnderflow:NOraiseOnDivideByZero:YES];

The NSRoundUp argument属性makes all operations round up to the nearest place. Other rounding options选项are NSRoundPlain, NSRoundDown, and NSRoundBankers, all of which are defined by NSRoundingMode. The scale: parameter参数defines the number of decimal places the resulting value should have, andthe rest of其余的the parameters参数define the exception-handling behavior of any operations. In this case, NSDecimalNumber will only raise an exception if you try to divide by zero.

NSRoundUp属性使所有的操作算到最近的位置,其他的进位选项是NSRoundPlain,NSRoundDown, 和NSRoundBankers,它们都被定义在NSRoundingMode,scale参数定义了结果值保留的小数位的数量,其余的参数给所有的操作定义了异常处理行为,这这个例子中,NSDecimalNumber将只捕获一个异常,如果你尝试除0.

This rounding behavior can then be passed to the decimalNumberByMultiplyingBy:withBehavior: method (or any of the other arithmetic methods), as shown below.

这个凑整的行为可以在之后被调用通过decimalNumberByMultiplyingBy:withBehavior:这个方法(或者任何其他的计算方法),如下所示.

NSDecimalNumber*subtotal = [NSDecimalNumberdecimalNumberWithString:@"40.98"];NSDecimalNumber*discount = [NSDecimalNumberdecimalNumberWithString:@".90"];NSDecimalNumber*total = [subtotal decimalNumberByMultiplyingBy:discount                                                      withBehavior:roundUp];NSLog(@"Rounded total: %@", total);

Now, instead of 36.882, the total gets rounded up to two decimal points, resulting in 36.89.

现在,代替36.882,这个total算到2个小数位,结果是36.89

Comparing NSDecimalNumbers

Like NSNumber, NSDecimalNumber objects should use the compare: method instead of the native inequality不等operators. Again, this ensures that values are compared, even if they are stored存储于in different instances. For example:

像NSNumber,NSDecimalNumber对象应该用compare:方法代替原生的不等式操作,此外,这确保了值被比较,即使他们存储于不通的实例中,例如

NSDecimalNumber*discount1 = [NSDecimalNumberdecimalNumberWithString:@".85"];NSDecimalNumber*discount2 = [NSDecimalNumberdecimalNumberWithString:@".9"];NSComparisonResultresult = [discount1 compare:discount2];if(result ==NSOrderedAscending) {NSLog(@"85%% < 90%%小于"); }elseif(result ==NSOrderedSame) {NSLog(@"85%% == 90%%等于");}elseif(result ==NSOrderedDescending) {NSLog(@"85%% > 90%%大于");}

NSDecimalNumber also inherits继承the isEqualToNumber: method from NSNumber.

NSDecimalNumber也从NSNumber中继承了isEqualToNumber:

Decimal Numbers in C

For most practical实用purposes目的, the NSDecimalNumber class should satisfy满足your fixed-point needs; however, it’s worth noting that there is also a function-based alternative available可用in pure纯C. This provides increased efficiency效率over the OOP interface discussed above and is thus preferred优先选择for high-performance性能applicationsdealing with处理a large number of calculations.

对于大多数实用的目的,NSDecimalNumber应该能满足你定点的需要,然而,值得注意的是也有一个基于纯C语言的基础函数,它相对面向对象编程提供了效率在上面的讨论中,因此我们优先选择它为了一个高性能的应用处理一个大数的计算

NSDecimal

Instead of an NSDecimalNumber object, the C interface is built around the NSDecimal struct. Unfortunately, the Foundation Framework doesn’t make it easy to create an NSDecimal from scratch. You need to generate生成one from a full-fledged成熟的NSDecimalNumber using its decimalValue method. There is a corresponding相应的factory工厂method, also shown below.

代替NSDecimalNumber对象,C实例创建了一个NSDecimal结构体,不幸的,Foundation Framework没有使它很容易的创建从scratch,你需要去生成一个从一个成熟的NSDecimalNumber用它的decimalValue方法,它是一个相应的工厂方法,也被展示如下

NSDecimalNumber*price = [NSDecimalNumberdecimalNumberWithString:@"15.99"];NSDecimalasStruct = [price decimalValue];NSDecimalNumber*asNewObject = [NSDecimalNumberdecimalNumberWithDecimal:asStruct];

This isn’t exactly准确的an ideal理想way to create NSDecimal’s, but once you have a struct representation of your initial初始values, you canstick to坚持the functional API presented below. All of these functions use struct’s as inputs and outputs.

它不是一个准确的理想的方法去创建一个NSDecimal’s,但是一旦你有一个结构展现了你的初始值,你可以一直坚持这个功能API被提出,所有的函数用struct作为输入和输出

Arithmetic Functions

In lieu of代替the arithmetic methods of NSDecimalNumber, the C interface uses functions like NSDecimalAdd(), NSDecimalSubtract(), etc. Instead of returning the result, these functions populate填入the first argument with the calculated value. This makes it possible to reuse an existing NSDecimal in several operations and avoid allocating分配unnecessary structs just to hold intermediary媒介values.

代替计算方法的是NSDecimalNumber,C的接口用函数像NSDecimalAdd(),NSDecimalSubtract()等.代替结果的返回值,这个函数填入了第一个参数用一个可计算的值,这使它可以重用一个存在的NSDecimal在几个操作,避免分配不必要的结构体仅仅是为了保存媒介值

For example, the following snippet片段uses a single result variable across 5 function calls. Compare this to the Arithmetic section, which created a new NSDecimalNumber object for each calculation.

例如,以下的片段用一个结果变量被函数调用了5次,和算法节每一次计算都创建一个NSDecimalNumber做比较,

NSDecimalprice1 = [[NSDecimalNumberdecimalNumberWithString:@"15.99"] decimalValue];NSDecimalprice2 = [[NSDecimalNumberdecimalNumberWithString:@"29.99"] decimalValue];NSDecimalcoupon = [[NSDecimalNumberdecimalNumberWithString:@"5.00"] decimalValue];NSDecimaldiscount = [[NSDecimalNumberdecimalNumberWithString:@".90"] decimalValue];NSDecimalnumProducts = [[NSDecimalNumberdecimalNumberWithString:@"2.0"] decimalValue]NSLocale*locale = [NSLocalecurrentLocale];NSDecimalresult;NSDecimalAdd(&result, &price1, &price2,NSRoundUp);NSLog(@"Subtotal: %@",NSDecimalString(&result, locale));NSDecimalSubtract(&result, &result, &coupon,NSRoundUp);NSLog(@"After coupon: %@",NSDecimalString(&result, locale));NSDecimalMultiply(&result, &result, &discount,NSRoundUp);NSLog(@"After discount: %@",NSDecimalString(&result, locale));NSDecimalDivide(&result, &result, &numProducts,NSRoundUp);NSLog(@"Average price per product: %@",NSDecimalString(&result, locale));NSDecimalPower(&result, &result,2,NSRoundUp);NSLog(@"Average price squared: %@",NSDecimalString(&result, locale));

Notice that these functions accept references to NSDecimal structs, which is why we need to use the reference operator (&) instead of passing them directly. Also note that rounding is an inherent固有的,与生俱来的part of each operation—it’s not encapsulated in a separate分开entity单独实体like NSDecimalNumberHandler.

主意到这些函数接受一个NSDecimal结构体的引用,这是为什么我们需要用一个取址符(&)代替直接使用它们,也主意到凑整是每一个操作固有的一部分,它没有像NSDecimalNumberHandler被封装在一个分开的单独实体中

The NSLocale instance defines the formatting格式化of NSDecimalString(), and is discussed讨论more thoroughly彻底in the Dates module.

NSLocale实例定义了NSDecimalString的格式化,讨论的更彻底在日期模块中

Error Checking

Unlike their OOP counterparts相对物, the arithmetic functions don’t raise exceptions when a calculation error occurs发生. Instead, they follow the common C pattern of using the return value to indicate表明,象征success or failure. All of the above上文的functions return an NSCalculationError, which defines what kind of error occurred. The potential可能的scenarios情景are demonstrated演示below.

不想它们的相对物面向对象编程,这个计算函数在计算错误发生时不会捕获异常,代替的是,它们允许普通的C模式用一个返回值去表明成功或者失败,所有上文的函数返回了一个NSCalculationError,它定义了发生了什么错误,这个可能的情景如下

NSDecimala = [[NSDecimalNumberdecimalNumberWithString:@"1.0"] decimalValue];NSDecimalb = [[NSDecimalNumberdecimalNumberWithString:@"0.0"] decimalValue];NSDecimalresult;NSCalculationErrorsuccess =NSDecimalDivide(&result, &a, &b,NSRoundPlain);switch(success) {caseNSCalculationNoError:NSLog(@"Operation successful");break;caseNSCalculationLossOfPrecision:NSLog(@"Error: Operation resulted in loss of precision");break;caseNSCalculationUnderflow:NSLog(@"Error: Operation resulted in underflow");break;caseNSCalculationOverflow:NSLog(@"Error: Operation resulted in overflow");break;caseNSCalculationDivideByZero:NSLog(@"Error: Tried to divide by zero");break;default:break;}

Comparing NSDecimals

Comparing NSDecimal’s works exactly正是like the OOP interface, except you use the NSDecimalCompare() function:

比较NSDecimals的工作正是面向对象编程的实例,除非你用NSDecimalCompare()这个函数

NSDecimaldiscount1 = [[NSDecimalNumberdecimalNumberWithString:@".85"] decimalValue];NSDecimaldiscount2 = [[NSDecimalNumberdecimalNumberWithString:@".9"] decimalValue];NSComparisonResultresult =NSDecimalCompare(&discount1, &discount2);if(result ==NSOrderedAscending) {NSLog(@"85%% < 90%%");}elseif(result ==NSOrderedSame) {NSLog(@"85%% == 90%%");}elseif(result ==NSOrderedDescending) {NSLog(@"85%% > 90%%");}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 8,574评论 0 23
  • 在今天的雪中,看见了一个人的背影 他穿一身黑色,戴着一顶帽子 冷不丁,我瞥了一眼 紧皱的眉头,沙哑的咳嗽 微微飘起...
    甜宋儿阅读 145评论 2 2
  • 多行注释: CTRL+K,CTRL+C 取消多行注释: CTRL+K,CTRL+U
    Mumuah阅读 93评论 0 0
  • 再忙,也要打电话…… 给父母打电话, “你们保重身体!” 给朋友打电话, “你们健康快乐”。 给自己打电话, “年...
    小剧在成长阅读 178评论 0 6
  • 一碗面
    Jennyone阅读 133评论 0 0