how to save a float to nsnumber with just two decimals - ios

I'm trying to save a float to an nsnumber but i just want to save it with two decimal places. I know I can do it by converting to an NSString first using this code
NSString* formattedNumber = [NSString stringWithFormat:#"%.02f", myFloat];
but seems clumsy. All I want to do is convert
float numb = 23.25454 into NSNumber 23.25

Use this
float numb = 23.25454;
NSNumber *num = #((int)(numb*100)/100.0);

Just round it using any of these functions
float rounded = round(val * 100) / 100;
float rounded_down = floorf(val * 100) / 100;
float nearest = floorf(val * 100 + 0.5) / 100;
float rounded_up = ceilf(val * 100) / 100;

If you're looking for an object oriented approach, try using NSDecimalNumber which is a subclass of NSNumber. Init the NSDecimalNumber with your float value and then call decimalNumberByRoundingAccordingToBehavior:. This gives you a few options of how the truncation or rounding occurs with NSDecimalNumberBehaviors, where you can set the scale (number of digits following the decimal) and an NSRoundingMode. Check the docs for more info.

It is impossible to do this with float, double, or either of those wrapped as an NSNumber. You need to understand how floating point works.
All these use binary numbers, you wish to represent a number with exactly two decimal places. A binary fraction is made up from a sum of 1/2, 1/4, 1/8, 1/16... while a decimal fraction is a sum of 1/10, 1/100, 1/1000... Not all values which can be represented as a sum of values in one of this series can be represented as a sum in the other. This is a similar issue to representing 1/3 in decimal, it is 3/10 + 3/100 + 3/1000 + .....
Try writing, for example, 0.17 = 17/100 = 1/10 + 7/100 as a sum of 1/2, 1/4 etc. Well it's 1/8 + 9/200 = 1/8 + 1/32 + 11/8000 (I'm just doing this on the fly, excuse any errors!) = you figure it out!
To address this there is the NSDecimalNumber class, which is a subclass of NSNumber and represents numbers in base-10. The class provides the basic operations to do base-10 arithmetic. You can't mix arithmetic easily between base-10 and base-2 numbers, you cannot even create an NSDecimalNumber directly from a float or double - you format the later as an NSString (i.e. convert them to a base-10 representation) - and extracting a double value with the doubleValue method is described as:
The approximate value of the receiver as a double.
Note the approximate.
So a long answer to get to a question: do you really want to store a float or double value to exactly two decimal places?
You can use the round, floor & ceil families to do it approximately, but be prepared for results that are "wrong". E.g. try:
float a = 371371.28127;
float b = roundf(a * 100.0) / 100.0;
NSLog(#"a: %f | b: %f", a, b);
HTH

NSDecimalNumber with NSDecimalNumberHandler is the best way to get accurate precisions if you want as Object. Below is the sample code.
-(NSDecimalNumber *)getRoundedNumberAfterPointDigitsCount:(int)digitsCount withDouble:(double)doubleValue{
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:#"%f",doubleValue]];
NSDecimalNumberHandler *decimalHandler = [[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundPlain scale:digitsCount raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
decimalNumber = [decimalNumber decimalNumberByRoundingAccordingToBehavior:decimalHandler];
return decimalNumber;
}
There is more of Rounding option available with NSRoundingMode.

float numb = 23.25454;
float myFloat = roundf(100 * numb) / 100.0;
NSNumber *number = [NSNumber numberWithFloat:myFloat];

Related

Multiplication of 2 decimal number values Objective C

I am doing multiplication of 2 values in Objective c which seems very simple yes but the result i get after multiplication is not correct the last digit after decimal point is changing the value. The code i used to do multiplication is below.
NSDecimalNumber* x = rpnStack.back(); rpnStack.pop_back();
NSDecimalNumber* y = rpnStack.back(); rpnStack.pop_back();
NSDecimalNumber* z = [y decimalNumberByMultiplyingBy:x]; // y * x;
The value of x = 20.16
The value of y = 51.3934970238095
The result of z is = 1036.0928999999995, which is should be 1036.0928999999996 as tested in many calculators. Can anyone give me some hint how can i fix this last number ?
NSDecimalNumber provides the correct answer. Try verifying the result by hand.
51.3934970238095
* 20.16
--------------------
3.083609821428570
5.13934970238095
0.0
+ 1027.869940476190
----------------------
1036.092899999999520
When you print NSDecimalNumber in console it rounds according to rounding behavior provided, usually default. Please refer to NSNumberFormatter and NSNumberFormatterRoundingMode when printing NSDecimalNumbers.
See:
https://developer.apple.com/reference/foundation/nsdecimalnumber?language=objc
https://developer.apple.com/reference/foundation/nsdecimalnumberhandler
https://developer.apple.com/reference/foundation/nsnumberformatter
I get the correct value by using NSNumber instead of NSDecimalNumber
NSNumber *x = #(20.16);
NSNumber *y = #(51.3934970238095);
NSNumber *z = #(x.doubleValue * y.doubleValue); //1036.0928999999996

Dynamic values in percentage format in Objective C

I want to know making Objective C variable values in percentage format. I am getting 6 values dynamically. Sometimes values might increase more than 100. For ex: Avalue=143, Bvalue=450, Cvalue=76, Dvalue=98, Evalue=123, Fvalue=56
how can i format each value under percentage format?
(Avalue * 100)/100.f
(Bvalue * 100)/100.f
(Cvalue * 100)/100.f
(Dvalue * 100)/100.f
(Evalue * 100)/100.f
(Fvalue * 100)/100.f
Is this proper way of doing it?
Well, percentage numbers are in essence fractions. In mathematics, a percentage is a number or ratio expressed as a fraction of 100.
if you want to compare numbers like in your case, compare each numbers to the sum oaf all value, then set the sum as 100%.
float sumAllValues = (Avalue + Bvalue + ...);
float aValuePercent = (Avalue / sumAllValues) * 100.f
you can format that percentage number with NSNumberFormatter
NSString *result1 = [NSNumberFormatter localizedStringFromNumber:[NSNumber numberWithFloat:aValuePercent];
numberStyle:NSNumberFormatterPercentStyle];
btw: why the variables begin with a Uppercase?
-Edit-
When you divide integers, keep in mind that integers divided by integer results integer.
I wrote a short example for the console.
NSInteger a = 5;
NSInteger b = 6;
NSInteger c = a * 100 / b;
NSInteger d = a / b * 100;
// example with conversion al values to float
float e = [[NSNumber numberWithInteger:a] floatValue] / [[NSNumber numberWithInteger:b] floatValue] * 100;
NSLog(#"resulting int c: %lu", c);
NSLog(#"resulting int d: %lu", d);
NSLog(#"resulting float e: %f", e);
2017-02-14 19:36:54.897 IntegerTest[2291:1238166] resulting int c: 83
2017-02-14 19:36:54.898 IntegerTest[2291:1238166] resulting int d: 0
2017-02-14 19:36:54.898 IntegerTest[2291:1238166] resulting float e: 83.333328
Program ended with exit code: 0
You see, when you multiply the first integer with 100 and the divide, you get 83.
The other way round (what is mathematically correct), first the division and after the multiply, you get 0, because 5/6 is less than 1 and the integer value is set to 0. Since multiplying 0 by any other value remains 0, the result is 0.
EDIT AGAIN -
the code from console is written with plain integers, but in essence they are the same as your values. First the multiplication, then the division.
NSInteger aPercentage = (Avalue * 100) / Bvalue;
or cast all values to floats. like so:
float aValueFloat = [[NSNumber numberWithInt:Avalue] floatValue];
EDIT AGAIN -
This was only for example reasons. Value is only the divisor because I do not know, to wash value you want to compare those values. In this example Avalue is compared to Bvalue, say Avalue is percent from Bvalue.
If you only want to print out Avlue = 143 in 143% then:
NSInteger aValue = 146;
NSString *aValuePercentString = [NSString stringWithFormat:#"%ld%%", aValue];
NSLog(#"%#", aValuePercentString);
Output: 2017-02-15 16:52:26.346 test[2132:1070601] 146%
Note1: This works with values as Integers. If the values are NSNumbers use %# instead of %ld.
Note2: Value is not an Integer anymore but a string.
Hope it helps!

iOS UInt64 number to float error

UInt64 intValue = 999999900;
float tt = intValue;
NSLog(#"float tt = %f", tt);
the output result is "float tt = 999999872", as you can see the UInt64 convert to float lose something, the Max float is bigger than 999999900, so I think the value 999999900 can be cast to float, so my question is why lose 28 in iOS?
float has a limited amount of precision. It's not the size of the number, it's the number of significant digits (9 in this case).
Use double instead of float to get more precision.
UInt64 intValue = 999999900;
double tt = intValue;
NSLog(#"double tt = %f", tt);
Why are you using float and not double? Has nobody told you that float has very limited precision (around 7 digits) while double has about 15 digits?
As a rule, you should NEVER use float instead of double unless you yourself can give a reasonable explanation why float would be more suitable than double.
So your question is: Why do I lose precision when I intentionally throw away 8 digits and precision, and what can I do? The answer is very simple: You lost precision because you threw it away yourself. Use double instead of float.

Converting NSString to float, the result is wrong

Here is the code:
NSString *val = #"51785239";
unsigned long long valFromFloat = 0L;
unsigned long long valFromLL = 0L;
valFromFloat = [val floatValue];
valFromLL = [val integerValue];
I was testing this code, the result is: valFromFloat = 51785240.0, valFromLL = 51785239.
Why valFromFloat is 51785240.0? I thought it should be 51785239.0.
Please, someone can explain it?
You seem to be confused over floating point vs. integer types, and misunderstand floating point precision.
Why valFromFloat is 51785240.0?
It isn't. valFromFloat is a variable of integer type, specifically unsigned long long, so its value certainly has no decimal fractional part.
The statement:
valFromFloat = [val floatValue];
first calls a method to parse (interpret) the string value val as a float value, which is the low precision floating-point type. That float value is then converted to an unsigned long long value and stored into valFromFloat.
Try:
float asFloat = [val floatValue];
double asDouble = [val doubleValue];
int asInt = [val intValue];
NSLog(#"float: %f | double: %f | int: %d", asFloat, asDouble, asInt);
and see what you get. Then lookup floating-point precision and the difference between binary floating-point, such as the types float and double, and decimal floating-point types, such as NSDecimal and NSDecimalNumber.
HTH
The float
The screenshot from MacTypes.h.
As we can see the float 【Float32】 is 32 bit IEEE float: 1 sign bit, 8 exponent bits, 23 fraction bits.
And we can get the bellow images from https://en.wikipedia.org/wiki/Single-precision_floating-point_format
Then we can convert the string to float as bellow:
51785239(10)=11000101100010111000010111(2)
Also IEEE 754 binary32 format requires that you represent real values in format, so that 11000101100010111000010111 is shifted to the right by 25 digits to become
From which we deduce:
The exponent is 25 (and in the biased form it is therefore 152 = 1001 1000)
The fraction is 1000101100010111000011000 (looking to the right 25 bits of the binary point whitch is rounding to 1000101100010111000011000)
thus:
Change
valFromFloat = [val floatValue];
to
valFromFloat = [val doubleValue];
(and think about what a float is).
NSString *string_val =#"51785239.65";
float float_val=[string_val floatValue];

Formatting an integer value

Im obtaining an int value from UITextField [self.dbRef.text intValue];
I want to then format that value so I can add a decimal place that precceds the number ie. If [self.dbRef.text intValue]; returns 4 i need that value to be 0.04
So far I have tried various ways including
float Y = ([self.dbRef.text intValue]/100);
slice.value = Y;
NSLog(#"float Y value = %f",Y);
returns zero
NSString* formatedTotalApplianceString = [NSString stringWithFormat:#"0.%#", self.dbRef.text];
NSLog(#"formated string = %#",formatedTotalApplianceString);
int totalAppliances = [formatedTotalApplianceString intValue];
NSLog(#"Resulting int value = %d",[formatedTotalApplianceString intValue]);
slice.value = totalAppliances;
NSLog(#"total appliances int value = %d",totalAppliances);
returns zero
You're doing an integer division, so the 0 value is correct in that context as integers cannot represent fractions (unless you're doing fixed point arithmetics, but that's a different can of worms). You need to do a floating point division, for example:
float Y = ([self.dbRef.text floatValue]/100.0f);
Either the [self.dbRef.text floatValue] or the 100.0f will turn this into a float division, because if the other side would be an int it would automatically get casted to a float. But the "best" way is to have both values of the same type.
Change
float Y = [self.dbRef.text intValue]/100;
to
float Y = ((float)[self.dbRef.text intValue])/100;
in your first variant.
Dividing int by int returns you int result even if then you assign it to float. 4/100 = 0 in such case.
The problem with [self.dbRef.text intValue]/100 is that it's an integer division. It drops the fraction. One way to work around it is to divide by 100.0:
[self.dbRef.text intValue]/100.0
However, this is not the most efficient way of doing it if all you need is adding a zero in front of a fraction: you could avoid float altogether by padding your printed int to two positions with leading zeros:
// If text is 4, the code below prints 0.04
NSLog(#"0.%02d", [self.dbRef.text intValue]);
The first code returns zero because you are performing an integer division, which produces an integer result. You should cast the value to a float.
The second code also returns zero because you're asking for the intValue of a floating point value. So the decimal part will be discarded.
NSString has also a floatValue method, you should use it to get a floating value. Once divided by 100 you will still have a floating point value (in a division if the quotient or the dividend is a float and the other an integer, the integer gets promoted to float):
float Y = ([self.dbRef.text floatValue]/100);
slice.value = Y;

Resources