How to safely create an NSInteger from an CGFloat? - iphone

I've got an CGFloat but need it as an NSInteger. The float value is like 2.0f, so I don't mind about fractional parts and loosing precision. What's a legal way to convert it into NSInteger without trouble (except the loss of precision, of course)?
NSInteger niceInt = niceCGFloat;
seems too simple, smells buggy. Maybe you can explain?

You want the c function lrintf() which rounds a floating point to a long int.

There's always the risk that 2.0f may actually be 1.9999999999f when represented in binary. Your conversion to int would then lead to 1 instead of 2.
To avoid this, I would add 0.5f to your float value. This would also have the effect of rounding your float, instead of truncating it.
NSInteger niceInt = niceCGFloat + 0.5f;

Related

NSString - Truncate everything after decimal point in a double

I have a double that I need only the value of everything before the decimal point.
Currently I am using
NSString *level = [NSString stringWithFormat:#"%.1f",doubleLevel];
but when given a value of 9.96, this returns "10". So it is rounding. I need it to return only the "9". (note - when the value is 9.95, it correctly returns the "9" value.)
Any suggestions?
Thank You.
Simply assign the float/double value to a int value.
int intValue = doubleLevel;
Cast that baby as an int.
int castedDouble = doubleLevel;
Anything after the . in the double will be truncated.
9.1239809384 --> 9
123.90454980 --> 123
No rounding, simple truncation.
If you want to keep it as a float:
CGFloat f = 9.99;
f = floorf(f);
there are quite a variety of floor and round implementations.
they have been around since UN*X, and are actually part of those low-level libraries, be they BSD, Posix, or some other variety - you should make yourself familiar with them.
there are different versions for different "depths" of floating point variables.
NSString *level = [NSString stringWithFormat:#"%d",doubleLevel];

Can I safely use CGFloat to hold Float64 or Float32 values?

I have an CGFloat property and sometimes I get a return value of type Float64 or also of type Float32. Could I store both safely to CGFloat?
From the headers:
// CGBase.h
typedef float CGFloat;
// MacTypes.h
typedef float Float32;
typedef double Float64;
So CGFloat and Float32 are both floats while Float64 is a double so you would lose precision.
(Edit to clarify: this is for 32 bit systems such as the iPhone. If you are building for 64 bit, CGFloat is defined as a double.)
It's best practice to always try and store scalar values in the same type as you received them because the precision of scalar types changes with the hardware.
CGFloat isn't always guaranteed to be the same size on all current and future hardware. If you substitute another type for it or use it to store another type, your code made break somewhere down the road.
You might gain or lose precision when a new iPhone/iPad comes out or the code might break if you try to port it to Macs.

Do I need to use decimal places when using floats? Is the "f" suffix necessary?

I've seen several examples in books and around the web where they sometimes use decimal places when declaring float values even if they are whole numbers, and sometimes using an "f" suffix. Is this necessary?
For example:
[UIColor colorWithRed:0.8 green:0.914 blue:0.9 alpha:1.00];
How is this different from:
[UIColor colorWithRed:0.8f green:0.914f blue:0.9f alpha:1.00f];
Does the trailing "f" mean anything special?
Getting rid of the trailing zeros for the alpha value works too, so it becomes:
[UIColor colorWithRed:0.8 green:0.914 blue:0.9 alpha:1];
So are the decimal zeros just there to remind myself and others that the value is a float?
Just one of those things that has puzzled me so any clarification is welcome :)
Decimal literals are treated as double by default. Using 1.0f tells the compiler to use a float (which is smaller than double) instead. In most cases it doesn't really matterĀ if a number is a double or a float, the compiler will make sure you get the right format for the job in the end. In high-performance code you may want to be explicit, but I'd suggest benchmarking it yourself.
As John said numbers with a decimal place default to double. TomTom is wrong.
I was curious to know if the compiler would just optimize the double to a const float (which I assumed would happen)... turns out it doesn't and the idea of the speed increase is actually legit... depending on how much you use it. In math-heavy application, you probably do want to use this trick.
It must be the case that it is taking the stored float variable, casting it to a double, performing the math against the double (the number without the f), then casting it back to a float to store it again. That would explain the diference in calculation even though we're storing in floats each time.
The code & raw results:
https://gist.github.com/1880400
Pulled out relevant benchmark on an iPad 1 in Debug profile (Release resulted in even more of a performance increase by using the f notation):
------------ 10000000 total loops
timeWithDoubles: 1.33593 sec
timeWithFloats: 0.80924 sec
Float speed up: 1.65x
Difference in calculation: -0.000038
Code:
int main (int argc, const char * argv[]) {
for (unsigned int magnitude = 100; magnitude < INT_MAX; magnitude *= 10) {
runTest(magnitude);
}
return 0;
}
void runTest(int numIterations) {
NSTimeInterval startTime = CFAbsoluteTimeGetCurrent();
float d = 1.2f;
for (int i = 0; i < numIterations; i++) {
d += 1.8368383;
d *= 0.976;
}
NSTimeInterval timeWithDoubles = CFAbsoluteTimeGetCurrent() - startTime;
startTime = CFAbsoluteTimeGetCurrent();
float f = 1.2f;
for (int i = 0; i < numIterations; i++) {
f += 1.8368383f;
f *= 0.976f;
}
NSTimeInterval timeWithFloats = CFAbsoluteTimeGetCurrent() - startTime;
printf("\n------------ %d total loops\n", numIterations);
printf("timeWithDoubles: %2.5f sec\n", timeWithDoubles);
printf("timeWithFloats: %2.5f sec\n", timeWithFloats);
printf("Float speed up: %2.2fx\n", timeWithDoubles / timeWithFloats);
printf("Difference in calculation: %f\n", d - f);
}
Trailing f: this is a float.
Trailing f + "." - redundant.
That simple.
8f is 8 as a float.
8.0 is 8 as a float.
8 is 8 as integer.
8.0f is 8 as a float.
Mostly the "f" can be style - to make sure it is a float, not a double.

Proper Usage and Formatting of a Float in Objective-C (or C)

I have an iPhone app. I am storing a float value, (distance), in my sqlite3 db. (The field in the db is formatted to float) I am able to store float values correctly in the db no problem. However, I can't seem to figure out how to pull the value back out of the db the format and present it correctly. Here is my code for pulling the value out of my db and using it:
NSString *itemDistance = [NSString stringWithFormat:#"%f",[item distance]];
float questionDistance = [itemDistance floatValue];
[item distance] is a float value. I can't get this to work. I get a REALLY long value instead. What am I doing wrong? Any help would be greatly appreciated.
Thank you in advance for your help,
L.
Assuming your -distance method is returning the right value, then this sounds like basic misunderstanding of how floats work in C. Common mistake. Every developer falls into this trap at least once.
Floating point numbers can actually only represent a fairly limited number of values. Specifically, unless you happen to choose a value that is exactly representable as a float, you'll get the nearest value, which will often have many decimal places of data.
The reason for this is because a float is only 32 bits; 4 bytes. Now, how many numbers with decimal points are there between 0..1000000 or 0..1000 or, even, 0..1. Infinite. Floats implement a very finite subset of possible numeric values and do so in a way where the resulting possible values may have many decimal places.
Consider:
printf("%5.18f\n", (float) 2.05);
printf("%5.18f\n", (float) 2.45);
printf("%5.18f\n", (float) 4200.75);
printf("%5.18f\n", (float) 37.89);
printf("%5.18f\n", (float) 1.2);
printf("%5.18f\n", (float) -1.2);
This prints:
2.049999952316284180
2.450000047683715820
4200.750000000000000000
37.889999389648437500
1.200000047683715820
-1.200000047683715820
Those values are as close to the values in the bit of code that a float could represent.
If you need more precision, use a double. More precision than that? Use NSDecimalNumber.
And, if you can, use CoreData. It makes managing this kind of thing a bit more straightforward.
why go round in circles?
NSString *itemDistance = [NSString stringWithFormat:#"%.2f",[item distance]];
float questionDistance = [itemDistance floatValue];
Where the .2 is saying I want 2 decimal places.
Whats the type of of distance? If it is an instance of NSNumber then I dont think the code you wrote will work, try
NSString *itemDistance = [[item distance] stringValue];
float questionDistance = [itemDistance floatValue];
or even
float q=[[item distance] floatValue];

Secure and valid way for converting a "float integer" into a natural integer?

I have a CGFloat that contains only "integers", in the meaning that it actually wants to represent integers only but due to float inprecision it may happen that it internally has a 23.00000000000000000000000142 or something like that. I try to feed an NSDecimalNumber with clean input, so I need to make sure this is truly a naked integer with no dirt. Well, I think this is a good way, but maybe I am wrong:
NSInteger *intVal = floatVal;
That would just get rid of those fragmental parts at the end of the tale, right? Or is there a more secure way to convert it into a true integer?
If you just want to take the integer part of a float then I believe you can just do the following:
CGFloat myfloat = 23.0000000000142f;
int myInt = (int) myfloat;