美文网首页
oc精度计算

oc精度计算

作者: Lv明 | 来源:发表于2017-05-12 11:52 被阅读0次

    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%%");}

    相关文章

      网友评论

          本文标题:oc精度计算

          本文链接:https://www.haomeiwen.com/subject/nbtsottx.html