问题
What is the difference between objective-c C primitive numbers? I know what they are and how to use them (somewhat), but I'm not sure what the capabilities and uses of each one is. Could anyone clear up which ones are best for some scenarios and not others?
- int
- float
- double
- long
- short
What can I store with each one? I know that some can store more precise numbers and some can only store whole numbers. Say for example I wanted to store a latitude (possibly retrieved from a CLLocation
object), which one should I use to avoid loosing any data?
I also noticed that there are unsigned
variants of each one. What does that mean and how is it different from a primitive number that is not unsigned?
Apple has some interesting documentation on this, however it doesn't fully satisfy my question.
回答1:
Well, first off types like int
, float
, double
, long
, and short
are C primitives, not Objective-C. As you may be aware, Objective-C is sort of a superset of C. The Objective-C NSNumber
is a wrapper class for all of these types.
So I'll answer your question with respect to these C primitives, and how Objective-C interprets them. Basically, each numeric type can be placed in one of two categories: Integer Types and Floating-Point Types.
Integer Types
- short
- int
- long
- long long
These can only store, well, integers (whole numbers), and are characterized by two traits: size and signedness.
Size means how much physical memory in the computer a type requires for storage, that is, how many bytes. Technically, the exact memory allocated for each type is implementation-dependendant, but there are a few guarantees: (1) char
will always be 1 byte (2) sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
.
Signedness means, simply whether or not the type can represent negative values. So a signed integer, or int
, can represent a certain range of negative or positive numbers (traditionally –2,147,483,648 to 2,147,483,647), and an unsigned integer, or unsigned int
can represent the same range of numbers, but all positive (0 to 4,294,967,295).
Floating-Point Types
- float
- double
- long double
These are used to store decimal values (aka fractions) and are also categorized by size. Again the only real guarantee you have is that sizeof(float) <= sizeof(double) <= sizeof (long double)
. Floating-point types are stored using a rather peculiar memory model that can be difficult to understand, and that I won't go into, but there is an excellent guide here.
There's a fantastic blog post about C primitives in an Objective-C context over at RyPress. Lots of intro CPS textbooks also have good resources.
回答2:
Firstly I would like to specify the difference between au unsigned int and an int
. Say that you have a very high number, and that you write a loop iterating with an unsigned int
:
for(unsigned int i=0; i< N; i++)
{ ... }
If N
is a number defined with #define
, it may be higher that the maximum value storable with an int
instead of an unsigned int
. If you overflow i
will start again from zero and you'll go in an infinite loop, that's why I prefer to use an int
for loops.
The same happens if for mistake you iterate with an int
, comparing it to a long
. If N
is a long
you should iterate with a long
, but if N
is an int
you can still safely iterate with a long
.
Another pitfail that may occur is when using the shift operator with an integer constant, then assigning it to an int
or long
. Maybe you also log sizeof(long)
and you notice that it returns 8
and you don't care about portability, so you think that you wouldn't lose precision here:
long i= 1 << 34;
Bit instead 1
isn't a long
, so it will overflow and when you cast it to a long you have already lost precision. Instead you should type:
long i= 1l << 34;
Newer compilers will warn you about this.
Taken from this question: Converting Long 64-bit Decimal to Binary.
About float
and double
there is a thing to considerate: they use a mantissa and an exponent to represent the number. It's something like:
value= 2^exponent * mantissa
So the more the exponent is high, the more the floating point number doesn't have an exact representation. It may also happen that a number is too high, so that it will have a so inaccurate representation, that surprisingly if you print it you get a different number:
float f= 9876543219124567;
NSLog("%.0f",f); // On my machine it prints 9876543585124352
If I use a double
it prints 9876543219124568
, and if I use a long double
with the .0Lf
format it prints the correct value. Always be careful when using floating points numbers, unexpected things may happen.
For example it may also happen that two floating point numbers have almost the same value, that you expect they have the same value but there is a subtle difference, so that the equality comparison fails. But this has been treated hundreds of times on Stack Overflow, so I will just post this link: What is the most effective way for float and double comparison?.
来源:https://stackoverflow.com/questions/17733890/difference-between-objective-c-primitive-numbers