How to efficiently convert a NSInteger into a NSDecimalNumber - ios

So I want to do NSInteger -> NSDecimalNumber for decimal computation purpose.
However, the way I am currently doing it, is using NSNumber as an intermediate.
NSInteger -> NSNumber -> NSDecimalNumber
NSInteger myInteger = 41234312;
NSDecimalNumber *myDecimal = [[NSNumber numberWithInteger:myInteger] decimalValue];
Is there a more efficient way to perform this conversion?

You don't need to convert it to NSNumber, You can use :
NSDecimalNumber *myDecimal = [NSDecimalNumber numberWithInteger:myInteger];
NSDecimal number is a subclass of NSNumber so you can directly use this method.

Related

How can I get NSDecimal to round to the nearest integer value?

I am using NSDecimal because I have to store extremely large values for my application. I would like to be able to use the NSDecimalDivide function to divide two NSDecimals and round the result to the nearest integer.
NSDecimal testOne = [[NSDecimalNumber decimalNumberWithString:#"1064"] decimalValue];
NSDecimal cost = [[NSDecimalNumber decimalNumberWithString:#"10"]decimalValue];
NSDecimal value;
NSDecimalDivide(&value, &testOne, &cost, NSRoundDown);
NSString *string = NSDecimalString(&value, _usLocale);
NSLog(#"Here is the cost%#",string);
This out puts 106.4 I would like it to output 106. Does anyone know how to round a NSDecimal number to the integer value?
Wrap the NSDecimal up as an NSDecimalNumber and use decimalNumberByRoundingAccordingToBehavior:. This lets you specify the exact rounding behavior you desire.
One possible way to do that is using a NSDecimalNumberHandler with scale set to 0.
NSDecimalNumber *number1 = [NSDecimalNumber decimalNumberWithString:#"1064"];
NSDecimalNumber *number2 = [NSDecimalNumber decimalNumberWithString:#"10"];
NSDecimalNumberHandler *behavior = [[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundDown
scale:0
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
NSDecimalNumber *result = [number1 decimalNumberByDividingBy:number2 withBehavior:behavior];
NSLog(#"Here is the cost %#", result);
Note that I am not using the primitive NSDecimal at all and you I would advise you the same.
However, if you want to work with NSDecimal directly, you can use the handy NSDecimalRound function.

How to divide NSDecimalNumber by integer?

I don't think a comprehensive, basic answer to this exists here yet, and googling didn't help.
Task: Given an NSDecimalNumber divide this by an int and return another NSDecimalNumber.
Clarification: amount_text below must be converted to a NSDecimalNumber because it is a currency. The result must be a NSDecimalNumber, but I don't care what format the divisor is.
What I have so far:
// Inputs
NSString *amount_text = #"15.3";
int n = 10;
NSDecimalNumber *total = [NSDecimalNumber decimalNumberWithString:amount_text];
// Take int, convert to string. Take string, convert to NSDecimalNumber.
NSString *int_string = [NSString stringWithFormat:#"%d", n];
NSDecimalNumber *divisor = [NSDecimalNumber decimalNumberWithString:int_string];
NSDecimalNumber *contribution = [total decimalNumberByDividingBy:divisor];
Surely, this can be done in a more straightforward way?
Is there any reason why you're using NSDecimalNumber? This can be done way easier like this:
// Inputs
NSString *amount_text = #"15.3";
int n = 10;
float amount = [amount_text floatValue];
float result = amount / n;
If you really want to do it with NSDecimalNumber:
// Inputs
NSString *amount_text = #"15.3";
int n = 10;
NSDecimalNumber *total = [NSDecimalNumber decimalNumberWithString:amount_text];
NSDecimalNumber *divisor = [NSDecimalNumber decimalNumberWithMantissa:n exponent:0 isNegative:NO];
NSDecimalNumber *contribution = [total decimalNumberByDividingBy:divisor];
You can always use initialisers when creating NSDecimalNumber. Since it is a subclass of NSNumber, NSDecimalNumber overrides initialisers.
So you can do
NSDecimalNumber *decimalNumber = [[NSDecimalNumber alloc] initWithInt:10];
however, you should be careful if your are doing high precision calculations as there are some problems using these initialisers. You can read about it here in more detail.
Alternatively (potentially losing some precision):
double amount = 15.3;
double n = 10.0;
double contribution = amount / n;
// conversion to decimal
NSString *string = [NSString stringWithFormat:#"%f", n];
NSDecimalNumber *contribution_dec = [NSDecimalNumber decimalNumberWithString:string];
better yet (if n=10):
[dec decimalNumberByMultiplyingByPowerOf10:-1];
As per your code...
You are creating an NSDecimalNumber from string and then doing manipulations with it.
I never do that. Unless you need NSDecimalNumber unless you want a boxed Objective-C Object, Avoid it, use float and double.
If you want to do it much simpler you can do it as:
float quotient = [total floatValue]/n;
or,
float quotient = [contribution floatValue]/n;
EDIT: If you want with any specific reason to use boxed type then you can use as:
NSString *amount_text = #"15.3";
int n = 10;
NSDecimalNumber *total = [NSDecimalNumber decimalNumberWithString:amount_text];
NSDecimalNumber *divisor = [[NSDecimalNumber alloc] initWithInt:n];
NSDecimalNumber *contribution = [total decimalNumberByDividingBy:divisor];

Convert long NSString to NSNumber

I am unable to reliably convert longer NSString to NSNumber. Specifically, I am converting MPMediaEntityPropertyPersistentID as a string to a NSNumber Sometimes it works, usually it doesn't.
Conversion code:
NSString *keke = [jsonArray objectForKey:#"next"];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *persistentIDasNumber = [f numberFromString:keke];
Here is an example of a successful string to number conversion:
String: 3813955856659208324
Number: 3813955856659208324
And here is an unsuccessful conversion:
String: 12790162104953153719
Number:1.279016210495315e+19
It's close but what is happening at the end? Is it too large?
Apparently the largest integer number that can be processed with NSNumberFormatter is long long, which is 9223372036854775807. Anything beyond that will lose precision and not come out as you put it in.
Instead use NSDecimalNumber, a concrete subclass of NSNumber. And it can even parse strings itself:
NSDecimalNumber *dn=[[NSDecimalNumber alloc]initWithString:#"12790162104953153719"];
NSLog(#"dn: %#",dn);
NSDecimalNumber can handle up to 38 digit long decimal numbers before it loses precision.
This is how you do it:
unsigned long long number = [[jsonArray objectForKey:#"next"] longLongValue];
NSNumber * numberValue = [NSNumber numberWithUnsignedLongLong:number];

NSDecimalNumber, addition, and just not sure

I'm not sure what to do next. They're just dollar amounts from a text field. I'm trying to add them together.
NSString *checkAmount = [checkAmountInput.text substringFromIndex:1];
NSDecimalNumber *checkAmountValue = (NSDecimalNumber*)[NSString stringWithFormat:#"%#",checkAmount];
NSLog(#"%#", checkAmountValue);
NSString *bankBalance = [bankBalanceInput.text substringFromIndex:1];
NSDecimalNumber *bankBalanceValue = (NSDecimalNumber*)[NSString stringWithFormat:#"%#",bankBalance];
NSLog(#"%#", bankBalanceValue);
NSDecimalNumber *totalAmount =
NSLog(#"%#",totalAmount);
When I try using decimalNumberByAdding I get:
'-[__NSCFString decimalNumberByAdding:]: unrecognized selector sent to instance 0x8a39a10'
Maybe I'm going about this all wrong... but I'm just starting out again.
Your checkAmountValue and bankBalanceValue aren't actually NSDecimalNumber instances. Casting an NSString to an NSDecimalNumber will silence a compiler warning, but the objects are still just strings.
You can use decimalNumberWithString: to create an actual NSDecimalNumber instance from a string:
NSString *bankBalance = [bankBalanceInput.text substringFromIndex:1];
NSDecimalNumber *bankBalanceValue = [NSDecimalNumber decimalNumberWithString:bankBalance];
There's some mixed up code there. Effectively, what you want to do is grab the text from two NSTextFields, and convert them to NSDecimalNumbers and add them. You can certainly do that. Be aware that NSTextField, can also 'parse' the string value directly and return you a numeric type (int, double, float) directly:
double d = [textField doubleValue];
If you still wanted to use NSDecimalNumber, and parse it from an NSString:
NSString *s = [textField stringValue];
To convert the string to an NSDecimalNumber:
NSDecimalNumber *n1 = [NSDecimalNumber decimalNumberWithString:s]
NSDecimalNumber *n2 = // repeat as above for the second string
To add them together:
NSDecimalNumber *n3 = [n1 decimalNumberByAdding:n2];
Note that, decimalNumberWithString is a class factory method which creates an instance of NSDecimalNumber by parsing a string. In your case you were simply casting to this which really doesn't create the type that you need.

NSNumber to float Value

When I convert NSNumber to float value using 'floatValue', there is a difference in precision. Example, I have a NSNumber 'myNumber' having value 2.3, and if I convert myNumber to float using 'floatValue', its value becomes, 2.29999. But I need exactly 2.30000. There is no problem with number of zeros after 2.3, I need '2.3' instead of '2.9'.
How can I do so?
I had similar situation where I was reading value and assigning it back to float variable again.
My Problem statement:
NSString *value = #"553637.90";
NSNumber *num = #([value floatValue]); // 1. This is the problem. num is set to 553637.875000
NSNumberFormatter *decimalStyleFormatter = [[NSNumberFormatter alloc] init];
[decimalStyleFormatter setMaximumFractionDigits:2];
NSString *resultString = [decimalStyleFormatter stringFromNumber:num]; // 2. string is assigned with rounded value like 553637.88
float originalValue = [resultString floatValue]; // 3. Hence, originalValue turns out to be 553637.88 which wrong.
Following worked for me after changing lines:
NSNumber *num = #([value doubleValue]); // 4. doubleValue preserves value 553637.9
double originalvalue = [resultString doubleValue]; // 5. While reading back, assign to variable of type double, in this case 'originalValue'
I hope this would be helpful. :)
If you need exact precision, don't use float. Use a double if you need better precision. That still won't be exact. You could multiply myNumber by 10, convert to an unsigned int and perform your arithmetic on it, convert back to a float or double and divide by 10 and the end result might be more precise. If none of these are sufficiently precise, you might want to look into an arbitrary precision arithmetic library such as GNU MP Bignum.
I've done the following but it is showing me correctly
NSNumber *num = [NSNumber numberWithFloat:2.3];
float f = [num floatValue];
NSLog(#"%f", f);
You can play with something like this:
float x = 2.3f;
NSNumber *n = [NSNumber numberWithFloat:x];
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setPositiveFormat:#"0.#"];
NSString *s = [fmt stringFromNumber:n];
float f = [s floatValue];

Resources