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.
Related
What is the correct way to perform this operation?
399.9 / 100
What I would expect to see is
3.999
but the result is
3.9989999999999997
The result you see is correct, it's just not what you want.
Doubles are not precise values. The double you get by writing 399.9 is actually the precise value.
399.8999999999999772626324556767940521240234375
That's the closest available double to the exact value 399.9. Any other double is at least as far away from 399.9 as that.
Then you divide by 100. Again, the result is not precise, but the closest double has the exact value
3.99899999999999966604491419275291264057159423828125
That differs from what you would get by writing 3.999, which is the exact value:
3.999000000000000110134124042815528810024261474609375
At every step, the double operations have minimized the error, but because you are doing multiple steps, the final result diverges from the double closest to the mathematical result.
What you need to do depends on what your actual requirements are.
If you want to always calculate with two significant digits, then I'd just multiply my numbers with 100 and do all the operations as integer operations, until the very last division by 100.
If you have an intermediate result and wants to round it to two digits, I'd do what Fy Z1K says:
result = (result * 100).round() / 100;
import 'dart:math';
double roundDouble(double value, int places){
double mod = pow(10.0, places);
return ((value * mod).round().toDouble() / mod);
}
then you would basically get
double num1 = roundDouble(12.3412, 2);
// 12.34
double num2 = roundDouble(12.5668, 2);
// 12.57
double num3 = roundDouble(-12.3412, 2);
// -12.34
double num4 = roundDouble(-12.3456, 2);
// -12.35
To make decimal operations you can use the decimal package.
final d = Decimal.parse;
print(d('399.9') / d('100')); // => 3.999
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];
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];
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;
When I run the following code ,
NSString* s= #"10000000.01";
float f = [s floatValue];
double d = [s doubleValue];
if(f > 10000000)
{
NSLog(#"Over Value");
}
else {
NSLog(#"OK Float");
}
if(d > 10000000)
{
NSLog(#"Over value");
}
else {
NSLog(#"OK Double");
}
The response is like following.
2013-04-19 17:07:29.284 float[2991:907] OK Float
2013-04-19 17:07:29.287 float[2991:907] Over value
Why float value changed to 10000000.00 instead of 10000000.01 ?
float is 32-bit while double is 64-bit. A float has fewer significant digits than double.
A float value doesn't store enough to hold the 10 digits of your 10000000.01.
Also see Difference between float and double for more details. That is about C/C++ but it applies to Objective-C as well.
Double
Represents a 64-bit floating-point number.
Has a precision of at least 15 decimal digits.
Float
Float represents a 32-bit floating-point number.
precision of Float can be as little as 6 decimal digits.
The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. In situations where either type would be appropriate, Double is preferred.
Precision
Float - 32-bit (7 digits) floating point precision
Double - 64-bit (15 digits) floating point precision
One bit is allocated for signed bit.
Memory requirement
Float - 4 bytes
Double - 8 bytes
Range
Float - within 1.2E-38 to 3.4E+38
Double - within 2.3E-308 to 1.7E+308