I have a value coming from an API server. The server stores it as BigDecimal on Postgres. On the iOS side, the value is of type __NSCFNumber. How do I get the absolute value for NSCFNumber?
My primary purpose is to further convert this number to a currency.
__NSCFNumber is an internal class that implements the NSNumber interface.
If you want a double:
NSNumber *myNumber = objectFromPostgres;
double value = fabs(myNumber.doubleValue);
If you want a long:
NSNumber *myNumber = objectFromPostgres;
long value = labs(myNumber.longValue);
If you want an int:
NSNumber *myNumber = objectFromPostgres;
int value = abs(myNumber.intValue);
You have a choice on the precision, but assuming a double value, you can use this:
NSNumber *number = [NSNumber numberWithDouble:-3.14159]; // isa Class __NSCFNumber 0x0000000101357a20
double absoluteValue = fabsl([number doubleValue]);
NSLog(#"absolute value = %f", absoluteValue);
Outputs:
absolute value = 3.141590
I asked an incomplete and vague question and I'm sorry. For my sins, I'm posting my solution and maybe it can help someone.
NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundUp
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
NSDecimalNumber *totalAmount = [NSDecimalNumber decimalNumberWithDecimal:[user[#"total"] decimalValue]];
totalAmount = [[self abs:totalAmount] decimalNumberByRoundingAccordingToBehavior:roundUp];
The helper method that I got from this SO question.
- (NSDecimalNumber *)abs:(NSDecimalNumber *)num {
if ([num compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// Number is negative. Multiply by -1
NSDecimalNumber * negativeOne = [NSDecimalNumber decimalNumberWithMantissa:1
exponent:0
isNegative:YES];
return [num decimalNumberByMultiplyingBy:negativeOne];
} else {
return num;
}
}
Related
How can I convert a NSString containing a number of any primitive data type (e.g. int, float, char, unsigned int, etc.)? The problem is, I don't know which number type the string will contain at runtime.
I have an idea how to do it, but I'm not sure if this works with any type, also unsigned and floating point values:
long long scannedNumber;
NSScanner *scanner = [NSScanner scannerWithString:aString];
[scanner scanLongLong:&scannedNumber];
NSNumber *number = [NSNumber numberWithLongLong: scannedNumber];
Thanks for the help.
Use an NSNumberFormatter:
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterDecimalStyle;
NSNumber *myNumber = [f numberFromString:#"42"];
If the string is not a valid number, then myNumber will be nil. If it is a valid number, then you now have all of the NSNumber goodness to figure out what kind of number it actually is.
You can use -[NSString integerValue], -[NSString floatValue], etc. However, the correct (locale-sensitive, etc.) way to do this is to use -[NSNumberFormatter numberFromString:] which will give you an NSNumber converted from the appropriate locale and given the settings of the NSNumberFormatter (including whether it will allow floating point values).
Objective-C
(Note: this method doesn't play nice with difference locales, but is slightly faster than a NSNumberFormatter)
NSNumber *num1 = #([#"42" intValue]);
NSNumber *num2 = #([#"42.42" floatValue]);
Swift
Simple but dirty way
// Swift 1.2
if let intValue = "42".toInt() {
let number1 = NSNumber(integer:intValue)
}
// Swift 2.0
let number2 = Int("42')
// Swift 3.0
NSDecimalNumber(string: "42.42")
// Using NSNumber
let number3 = NSNumber(float:("42.42" as NSString).floatValue)
The extension-way
This is better, really, because it'll play nicely with locales and decimals.
extension String {
var numberValue:NSNumber? {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter.number(from: self)
}
}
Now you can simply do:
let someFloat = "42.42".numberValue
let someInt = "42".numberValue
For strings starting with integers, e.g., #"123", #"456 ft", #"7.89", etc., use -[NSString integerValue].
So, #([#"12.8 lbs" integerValue]) is like doing [NSNumber numberWithInteger:12].
You can also do this:
NSNumber *number = #([dictionary[#"id"] intValue]]);
Have fun!
If you know that you receive integers, you could use:
NSString* val = #"12";
[NSNumber numberWithInt:[val intValue]];
Here's a working sample of NSNumberFormatter reading localized number NSString (xCode 3.2.4, osX 10.6), to save others the hours I've just spent messing around. Beware: while it can handle trailing blanks ("8,765.4 " works), this cannot handle leading white space and this cannot handle stray text characters. (Bad input strings: " 8" and "8q" and "8 q".)
NSString *tempStr = #"8,765.4";
// localization allows other thousands separators, also.
NSNumberFormatter * myNumFormatter = [[NSNumberFormatter alloc] init];
[myNumFormatter setLocale:[NSLocale currentLocale]]; // happen by default?
[myNumFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
// next line is very important!
[myNumFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; // crucial
NSNumber *tempNum = [myNumFormatter numberFromString:tempStr];
NSLog(#"string '%#' gives NSNumber '%#' with intValue '%i'",
tempStr, tempNum, [tempNum intValue]);
[myNumFormatter release]; // good citizen
I wanted to convert a string to a double. This above answer didn't quite work for me. But this did: How to do string conversions in Objective-C?
All I pretty much did was:
double myDouble = [myString doubleValue];
Thanks All! I am combined feedback and finally manage to convert from text input ( string ) to Integer. Plus it could tell me whether the input is integer :)
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:thresholdInput.text];
int minThreshold = [myNumber intValue];
NSLog(#"Setting for minThreshold %i", minThreshold);
if ((int)minThreshold < 1 )
{
NSLog(#"Not a number");
}
else
{
NSLog(#"Setting for integer minThreshold %i", minThreshold);
}
[f release];
I think NSDecimalNumber will do it:
Example:
NSNumber *theNumber = [NSDecimalNumber decimalNumberWithString:[stringVariable text]]];
NSDecimalNumber is a subclass of NSNumber, so implicit casting allowed.
What about C's standard atoi?
int num = atoi([scannedNumber cStringUsingEncoding:NSUTF8StringEncoding]);
Do you think there are any caveats?
You can just use [string intValue] or [string floatValue] or [string doubleValue] etc
You can also use NSNumberFormatter class:
you can also do like this code 8.3.3 ios 10.3 support
[NSNumber numberWithInt:[#"put your string here" intValue]]
NSDecimalNumber *myNumber = [NSDecimalNumber decimalNumberWithString:#"123.45"];
NSLog(#"My Number : %#",myNumber);
Try this
NSNumber *yourNumber = [NSNumber numberWithLongLong:[yourString longLongValue]];
Note - I have used longLongValue as per my requirement. You can also use integerValue, longValue, or any other format depending upon your requirement.
Worked in Swift 3
NSDecimalNumber(string: "Your string")
I know this is very late but below code is working for me.
Try this code
NSNumber *number = #([dictionary[#"keyValue"] intValue]]);
This may help you. Thanks
extension String {
var numberValue:NSNumber? {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter.number(from: self)
}
}
let someFloat = "12.34".numberValue
I'm trying to convert a double to an NSDeciamlNumber. Here is my code:
- (NSDecimalNumber *)myMethod {
double amount = 42;
...
return [NSDecimalNumber numberWithDouble:amount]; // Get warning here
}
But I get the following warning:
Incompatible pointer types returning 'NSNumber *' from a function with result type 'NSDecimalNumber *'
What am I doing wrong, and how can I fix it?
numberWithDouble: method of NSDecimalNumber returns NSNumber.
In your method you want to return decimal so its OK if you allocate a new NSDecimalNumber with the decimal value (amount in your example).
May use the following way to get rid of the error:
-(NSDecimalNumber *)myMethod
{ double amount = 42; ...
return [[NSDecimalNumber alloc] initWithDouble: amount];
}
According to documentation [NSDecimalNumber numberWithDouble:_] returns a NSNumber so you should change the method declaration
- (NSNumber *)myMethod {
double amount = 42;
...
return [NSDecimalNumber numberWithDouble:amount]; // Get warning here
}
Try this. It may work out
- (NSNumber *)myMethod {
double amount = 42;
[NSNumber numberWithDouble:amount]
return [NSDecimalNumber numberWithDouble:amount];
}
numberWithDouble: method returns an NSNumber object but you suppose to return NSDecimalNumber.
Change it to
- (NSDecimalNumber *)myMethod {
double amount = 42;
return [[NSDecimalNumber alloc]initWithDouble:amount];
}
Try below code-
- (NSDecimalNumber *)myMethod {
double amount = 42;
...
return [[NSDecimalNumber alloc] initWithDouble: amount];
}
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];
I have to prevent the value from rounding off after the decimal.
Here is the code I use :
NSNumberFormatter* nf = [[[NSNumberFormatter alloc] init] autorelease];
nf.positiveFormat = #"0.###";
NSString* trimmedValue = [nf stringFromNumber: [NSNumber numberWithFloat:[exRateLabel doubleValue]*amount]];
trimmedValue = [trimmedValue substringToIndex:[trimmedValue length]-1];
In this case, if I multiply 1000 * 50.1234 I'm getting 50123.3984, but it should be 50123.4.
NSLog(#".2f",50.1234*1000);
For this case it's showing the correct value but for
NSLog(#".2f",50.1234*123);
it is rounding off the actual value, which is 6165.1782, to 6165.18.
Just use double instead of float and a proper rounding rule:
NSNumberFormatter* nf = [[NSNumberFormatter alloc] init];
nf.positiveFormat = #"0.###";
nf.roundingMode = NSNumberFormatterRoundFloor;
NSString* trimmedValue = [nf stringFromNumber: [NSNumber numberWithDouble:50.1234*123]];
NSLog(#"trimmedValue: %#", trimmedValue);
And the result is:
trimmedValue: 6165.178
If the mathematics is required to be precise, I'd suggest using an NSDecimalNumber.
NSDecimalNumber *myNumber = [[NSDecimalNumber alloc] initWithMantissa:501234 exponent:-4 isNegative:NO]];
NSDecimalNumber *answer = [self multiplyDecimalNumber:myNumber with:[NSDecimalNumber decimalNumberWithMantissa:1000 exponent:0 isNegative:NO];
NSLog(#"Answer: %g", floor([answer doubleValue]));
I made a quick wrapper for the multiplication, I never wanted an exception, your needs may be different:
-(NSDecimalNumber *) multiplyDecimalNumber:(NSDecimalNumber *) lhs with:(NSDecimalNumber *) rhs {
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:NSDecimalNoScale raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
return [lhs decimalNumberByMultiplyingBy:rhs withBehavior:handler];
}
They are both correct.
First, I believe you have a typo - you're missing the %.
NSLog(#"%.2f", 50.1234*1000); // same as #"%.2f", 50,123.4 = #"50123.4"
the math leaves you with a clean 1/10th, even though you are asking for 2 decimal places to be printed.
NSLog(#"%.2f",50.1234*123); // same as #"%.2f", 5,161.1782 = #"5161.18"
you are asking for two decimal numbers and rounding up is the default behavior.
It sounds like the formatting you actually want to use is:
NSLog(#"%.1f", number);
or if you want a forced, zero-padded two digits, use
NSLog(#"%.02", number); // first case would come out #"50123.40"
this will force all trailing zeros to be printed
you are probably using a 'double' representation, cast the number to a float or you can use your own policy for truncation using functions like:
float roundUp (float value, int digits) {
int mod = pow(10, digits);
float roundedUp = value;
if (mod != 0) {
roundedUp = ceilf(value * mod) / mod;
}
return roundedUp;
}
float roundDown (float value, int digits) {
int mod = pow(10, digits);
float roundedDown = value;
if (mod != 0) {
roundedDown = floorf(value * mod) / mod;
}
return roundedDown;
}
float nearestf (float value, int digits) {
int mod = pow(10, digits);
float nearest = value;
if (mod != 0) {
nearest = floorf(value*mod + 0.5) / mod;
}
return nearest;
}
'roundUp' should be the one you need, or try with the more generic 'nearestf'
For me it was requirement to show atleast two decimal and maximum decimal number.
Following code did worked for me.
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:2];
[numberFormatter setMinimumFractionDigits:2];
[numberFormatter setRoundingMode:NSNumberFormatterRoundDown];
NSString *num = #"123456.019";
NSString *stringFromNumber = [numberFormatter stringFromNumber:[numberFormatter numberFromString:num]];
NSLog(#"check this %#", stringFromNumber);
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];