simple question about assigning float to int - objective-c

This is probably something very simple but I'm not getting the results I'm expecting. I apologise if it's a stupid question, I just don't what to google for.
Easiest way to explain is with some code:
int var = 2.0*4.0;
NSLog(#"%d", 2.0*4.0);//1
NSLog(#"%d", var);//2
if ((2.0*4.0)!=0) {//3
NSLog(#"true");
}
if (var!=0) {//4
NSLog(#"true");
}
This produces the following output:
0 //1
8 //2
true //3
true //4
The one that I don't understand is line //1. Why are all the others converting (I'm assuming the correct word is "casting", please correct me if I'm wrong) the float into an int, but inside NSLog it's not happening. Does this have something to do with the string formatting %d parameter and it being fussy (for lack of a better word)?

You're telling NSLog that you're passing it an integer with the #"%d" format specifier, but you're not actually giving it an integer; you're giving it a double-precision floating-point value (8.0, as it happens). When you lie to NSLog, its behavior is undefined, and you get unexpected results like this.
Don't lie to NSLog. If you want to convert the result of 2.0*4.0 to an integer before printing, you need to do that explicitly:
NSLog(#"%d", (int)(2.0*4.0));
If, instead, you want to print the result of 2.0*4.0 as a double-precision floating-point number, you need to use a different format specifier:
NSLog(#"%g", 2.0*4.0);
More broadly, this is true of any function that takes a variable number of arguments and some format string to tell it how to interpret them. It's up to you to make sure that the data you pass it matches the corresponding format specifiers; implicit conversions will not happen for you.

First, you never used floats in your program. They are doubles.
Second, the arguments of NSLog, printf and the likes are not automatically converted to what you specify using %d or %f. It follows the standard promotion rule for untyped arguments. See the ISO specification, sec 6.5.2.2.6 and 6.5.2.2.7. Note the super weird rule that inside these functions,
a float is automatically promoted to double,
and any integer smaller than an int is promoted to int. (see 6.3.1.1.2)
So, strictly speaking, the specification %f is not showing a float, but a double. See the same document, Sec. 7.19.6.1.8.
Note also that in your case 1 and 3, promotions are to double.

In examples 2, 3 and 4, the float is either being assigned to an int (which converts it) or compared with an int (which also converts it). In 1, however, you're passing the float as an argument to a function. The printf function allows all the arguments after the initial format string to be of any type, so this is valid. But since the compiler doesn't know you mean for it to be an int (remember, you haven't done anything to let the compiler know), the float is passed along as a floating-point value. When printf sees the %d formatting specifier, it pops enough bytes for an int from the argument list and interprets those bytes as an int. Those bytes happen to look like an integer 0.

The format string %d expects a decimal number, meaning a base 10 integer, not a floating point. What you want there is %f if you're trying to get it to print out 8.0

The first parameter to NSLog is a format string, then the second (and subsequent) parameters can be any types. The compiler doesn't know what the types should be at compile time and so doesn't try to cast them to anything. At run time NSLog assumes the second (and subsequent) parameters are as specified in the format string. If there's a mismatch unexpected and generally unhappy things happen.
Summary; Make sure you pass variables of the right type in the second (and subsequent) parameter.

Related

how it's possible to assign a Float64 to an NSInteger variable?

How this function can work ?
- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format {
Float64 maxSupportedFramerate = 0;
for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) {
maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate);
}
return fmin(maxSupportedFramerate, kFramerateLimit);
}
because return fmin(maxSupportedFramerate, kFramerateLimit); it's an float64 not an NSInteger?
Because Objective-C is C, and the C specification states:
6.3 Conversions
6.3.1 Arithmetic operands
6.3.1.4 Real floating and integer
1 When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.
See also the definition of the return statement for why arithmetic conversion applies in this case:
6.8.6.4 The return statement
3 If a return statement with an expression is executed, the value of the expression is returned to the caller as the value of the function call expression. If the expression has a type different from the return type of the function in which it appears, the value is converted as if by assignment to an object having the return type of the function.
And then go read up on 6.5.16.1.3 Simple assignment.... you can keep going down the rabbit hole of the spec, as deep as you like. :D
But the key point is, in C, floating point values can be implicitly converted to integers, and there is specified way that thy are converted.
To be more clear, you can add an explicit cast:
return (NSInteger)fmin(maxSupportedFramerate, kFramerateLimit);
But that is not changing the behaviour as it will be done automatically as Rob explained.

Option Strict On and Constant in Visual Basic?

Please forgive me, I haven't used this site very much! I am working in Visual Studio with Visual Basic. I finished programming my project with Option Strict Off, then when I turned Option Strict on, I was alerted that this code was wrong:
Const TAX_Decimal As Decimal = 0.07
The explanation was that "Option Strict On disallows implicit conversions from 'Double' to 'Decimal'"
But I thought I had declared it as a decimal! It made me change it to:
Const TAX_Decimal As Decimal = CDec(0.07)
The only thing I did with this constant was multiply it by a decimal and saved it to a variable declared as a decimal!
Can someone tell me why this is happening?
Double is 8 bytes and Decimal is 16 bytes. Option Strict prevents from automatic type conversion. By default if you write a number with decimals in VB.NET it is considered as double and not decimal. For saying decimal you have to use some character to specify (I thing for decimal is m) so if you declare
Const VAR as decimal = 0.07m
then you wont require casting.
When the compiler sees a numeric literal, it selects a type based upon the size of the number, punctuation marks, and suffix (if any), and then translates the the sequence of characters in it to that type; all of this is done without regard for what the compiler is going to do with the number. Once this is done, the compiler will only allow the number to be used as its own type, explicitly cast to another type, or in the two cases defined below implicitly converted to another type.
If the number is interpreted as any integer type (int, long, etc.) the compiler will allow it to be used to initialize any integer type in which the number is representable, as well as any binary or decimal floating-point type, without regard for whether or not the number can be represented precisely in that type.
If the number is type Single [denoted by an f suffix], the compiler will allow it to be used to initialize a Double, without regard for whether the resulting Double will accurately represent the literal with which the Single was initialized.
Numeric literals of type Double [including a decimal point, but with no suffix] or Decimal [a "D" suffix not followed immediately by a plus or minus] cannot be used to initialize a variable of any other, even if the number would be representable precisely in the target type, or the result would be the target type's best representation of the numeric literal in question.
Note that conversions between type Decimal and the other floating-point types (double and float) should be avoided whenever possible, since the conversion methods are not very accurate. While there are many double values for which no exact Decimal representation exists, there is a wide numeric range in which Decimal values are more tightly packed than double values. One might expect that converting a double would choose the closest Decimal value, or at least one of the Decimal values which is between that number and the next higher or lower double value, but the normal conversion methods do not always do so. In some cases the result may be off by a significant margin.
If you ever find yourself having to convert Double to Decimal, you're probably doing something wrong. While there are some operations which are available on Double that are not available on Decimal, the act of converting between the two types means whatever Decimal result you end up with is apt to be less precise than if all computations had been done in Double`.

Cleanest way to convert a `Double` or `Single` to `Integer`, without rounding

Converting a floating-point number to an integer using either CInt or CType will cause the value of that number to be rounded. The Int function and Math.Floor may be used to convert a floating-point number to a whole number, rounding toward negative infinity, but both functions return floating-point values which cannot be implicitly used as Integer values without a cast.
Is there a concise and idiomatic alternative to IntVar = CInt(Int(FloatingPointVar));? Pascal included Round and Trunc functions which returned Integer; is there some equivalent in either the VB.NET language or in the .NET framework?
A similar question, CInt does not round Double value consistently - how can I remove the fractional part? was asked in 2011, but it simply asked if there was a way to convert a floating-point number to an integer; the answers suggested a two-step process, but it didn't go into any depth about what does or does not exist in the framework. I would find it hard to believe that the Framework wouldn't have something analogous to the Pascal Trunc function, given that such a thing will frequently be needed when performing graphical operations using floating-point operands [such operations need to be rendered as discrete pixels, and should be rounded in such a way that round(x)-1 = round(x-1) for all x that fit within the range of +/- (2^31-1); even if such operations are rounded, they should use Floor(x+0.5), rather than round-to-nearest-even, so as to ensure the above property]
Incidentally, in C# a typecast from Double to Int using (type)expr notation uses round-to-zero semantics; the fact that this differs from the VB.NET behavior suggests that one or both languages is using its own conversion routines rather an explicit conversion operator included in the Framework. It would seem likely that the Framework should define a conversion operator? Does such an operator exist within the framework? What does it do? Is there a way to invoke it from C# and/or VB.NET?
After some searching, it seems that VB has no clean way of accomplishing that, short of writing an extension method.
The C# (int) cast translates directly into conv.i4 in IL. VB has no such operators, and no framework function seems to provide an alternative.
Usenet had an interesting discussion about this back in 2005 – of course a lot has changed since then but I think this still holds.
You can use the Math.Truncate method.
Calculates the integral part of a specified double-precision floating-point number.
For example:
Dim a As double = 1.6666666
Dim b As Integer = Math.Truncate(a) ' b = 1
I know this is an old case but I saw no one suggest the Math.Round() function.
Yes Math.Round takes a double and returns a double. However it returns a number that has been rounded to a whole number. It should easily and concisely convert to an integer using cInt. Would that suffice?
cInt(math.round(10000.54564)) ' = 10001
cInt(math.round(10000.49564)) ' = 10000
You may need extract the Int part of a float number:
float num = 12.234;
string toint = "" + num;
string auxil = toint.Split('.');
int newnum = Int.Parse(auxil[0]);

Objective-C float string formatting: Formatting the whole numbers

There are some great answers here about how to format the decimal places of a float for a string:
float myFloatA = 2.123456f;
NSLog(#"myFloatA: [%.2f]", myFloatA;
// returns:
// myFloatA: [2.12]
But what I'm looking for is how to format the whole numbers of the same float. This can be done with the same sort of trick on an integer:
int myInt = 2;
NSLog(#"myInt: [%5d]", myInt;
// returns:
// myInt: [ 2]
So I was hoping something like a %5.2f would be the answer to formatting both before and after the decimal. But it doesn't:
float myFloatA = 2.123456f;
NSLog(#"myFloatA: [%5.2f]", myFloatA;
// returns:
// myFloatA: [2.12]
Any thoughts on this one?
Using the print specifiers is all very well for NSLogs, but think about this another way.
Usually, you want a string representation of a number when you are displaying it in something like a text field. In which case, you might as well use an NSNumberFormatter which does most of the heavy lifting for you.
Also confirmed that this works. If you're worried you're not getting 5 character width, try forcing zero padding with:
NSLog(#"myFloatA: [%05.2f]", myFloatA);

How to get float value as it is from the text box in objective c

Can any one please help me how to get float value as it is from text box
for Ex: I have entered 40.7
rateField=[[rateField text] floatValue];
I am getting rateField value as 40.7000008 but I want 40.7 only.
please help me.
thanks in advance
Thanks Every body,
I tried all the possibilities but I am not able to get what I want. I am not looking to print the value to convert into string.I want to use that value for computation. If i use Number Formatter again when i am converting from number to float it is giving same problem.So i want float value only but it should be whatever i have given in the text box it should not be padded with any values.This is my requirement.Please help me.
thanks&regards Balu
Thanks Every body,
I tried all the possibilities but I am not able to get what I want. I am not looking to print the value to convert into string.I want to use that value for computation. If i use Number Formatter again when i am converting from number to float it is giving same problem.So i want float value only but it should be whatever i have given in the text box it should not be padded with any values.This is my requirement.Please help me.
thanks&regards
Balu
This is ok. There is not guaranteed that you will get 40.7 if you will use even double.
If you want to output 40.7 you can use %.1f or NSNumberFormatter
Try using a double instead. Usually solves that issue. Has to do with the storage precision.
double dbl = [rateField.text doubleValue];
When using floating point numbers, these things can happen because of the way the numbers are stored in binary format in the computers memory.
It's similar to the way 1/3 = 0.33333333333333... in decimal numbers.
The best way to deal with this is to use number formatters in the textbox that displays the value.
You are already resolved float value.
Floating point numbers have limited precision. Although it depends on
the system, float relative error due to rounding will be around 1.1e-8
Non elementary arithmetic operations may give larger errors, and, of
course, error progragation must be considered when several operations
are compounded.
Additionally, rational numbers that are exactly representable as
floating point numbers in base 10, like 0.1 or 0.7, do not have an
exact representation as floating point numbers in base 2, which is
used internally, no matter the size of the mantissa. Hence, they
cannot be converted into their internal binary counterparts without a
small loss of precision. This can lead to confusing results: for
example, floor((0.1+0.7)*10) will usually return 7 instead of the
expected 8, since the internal representation will be something like
7.9999999999999991118....
So if you're using those numbers for output, you should use some rounding mechanism, even for double values.