ios issue with log calculation - objective-c

I am working on a calculation for free space loss and hitting a snag.
Doing this calculation:
fslLoss = 36.6 + (20 * log(fromAntenna/5280)) + (20 * log(serviceFreq))
Where fslLoss is a float and fromAntenna and servicefreq are integers:
NSLog(#"the freespace Loss is %0.01f", fslLoss);
The result is "the freespace Loss is -inf"
The issue appears to be in the 20log(fromAntenna/5280) section, as I get normal results without it.
BTW ... tried log10 with the same results.
Thanks for the help,
padapa

You say fromAntenna is an integer, so fromAntenna/5280 will be calculated with integer arithmetic. That means it will be rounded (floored, technically), probably not what you intended.
Fix it with:
log( (double) fromAntenna / 5280.0 )

log(0) is -inf. The integer division inside the logarithm may be zero. Use fromAntenna/5280.0 to get float division.

The compiler is correctly using fromAntenna & serviceFreq as ints and that's not giving you good results when fslLoss is a float. Use some float casts and you'll have better luck:
fslLoss = 36.6 + (20 * log((float)fromAntenna/5280)) + (20 * log((float)serviceFreq));

Related

Strange result of floating-point operation

Problems like this drive me crazy. Here's the relevant piece of code:
Dim RES As New Size(Math.Floor(Math.Round(mPageSize.Width - mMargins.Left - mMargins.Right - mLabelSize.Width, 4) / (mLabelSize.Width + mSpacing.Width) + 1),
Math.Floor((mPageSize.Height - mMargins.Top - mMargins.Bottom - mLabelSize.Height) / (mLabelSize.Height + mSpacing.Height)) + 1)
Values of the variables (all are of Single type):
mPageSize.Width = 8.5
mMargins.Left = 0.18
mMargins.Right = 0.18
mLabelSize.Width = 4.0
mSpacing.Width = 0.14
For God-knows-what reason, RES evaluates to {Width=1,Height=5} instead of {Width=2,Height=5}. I have evaluated the expressions on the right-side individually and as a whole and they correctly evaluate to {2,5}, but RES would never get correct value. Wonder what am I missing here.
EDIT
I have simplified the problem further. The following code will produce 2.0 if you QuickWatch the RHS, but the variable on the LHS will get 1.0 after you execute this line:
Dim X = Math.Floor(Math.Round(mPageSize.Width - mMargins.Left - mMargins.Right - mLabelSize.Width, 4) / (mLabelSize.Width + mSpacing.Width) + 1)
Time for MS to check it out?
EDIT 2
More info. The following gives correct results:
Dim Temp = mPageSize.Width - mMargins.Left - mMargins.Right - mLabelSize.Width
Dim X = Math.Floor(Temp / CDec(mLabelSize.Width + mSpacing.Width)) + 1
The problem is that the following expression evaluates to a value just below 1:
Math.Round(mPageSize.Width - mMargins.Left - mMargins.Right - mLabelSize.Width, 4) / (mLabelSize.Width + mSpacing.Width)
= 0.99999999985602739 (Double)
But what's the reason for that? The truth is that I don't know exactly. The MSDN does not offer enough information about the implementation of / but here's my guess:
Math.Round returns a Double with value 4.14. The right-hand side of the division is a Single. So you're dividing a Double by a Single. This results in a Double (see MSDN). So far, so good. The MSDN states that all integral data types are widened to Double before the division. Although Single is not an integral data type, this is probably what happens. And here is the problem. The widening does not seem to be performed on the result of the addition, but on its operands.
If you write
Dim sum = (mLabelSize.Width + mSpacing.Width) 'will be 4.14 Single
Math.Round(mPageSize.Width - mMargins.Left - mMargins.Right - mLabelSize.Width, 4) / sum
= 1 (Double)
Here sum is converted to double (resulting in 4.14) and everything is fine. But, if we convert both operands to double, then the conversion of 0.14 introduces some floating point error:
Dim dblLabelSizeWidth As Double = mLabelSize.Width ' will be 4.0
Dim dblSpacing As Double = mSpacing.Width ' will be 0.14000000059604645
The sum is slightly bigger than 4.14, resulting in a quotient slightly smaller than 1.
So the reason is that the conversion to double is not performed on the division's operand, but on the operand's operands, which introduces floating point errors.
You could overcome this problem by adding a small epsilon to the quotient before rounding off. Alternatively you might consider using a more precise data type such as Decimal. But at some point, there will also be floating-point errors with Decimal.
This is due to rounding error: you're taking the floor of a value that is very close to 2, but is less than 2 (while the mathematical value is 2). You should do all your computations with integers, or take rounding errors into account before using operations like floor (not always possible if you want the true value).
EDIT: Since vb.net has a Decimal datatype, you can also use it instead of integers. It may help in some cases like here: the base conversions for 0.18 and 0.14 (not representable exactly in binary) are avoided and the additions and subtractions will be performed exactly here, so that the operands of the division will be computed exactly. Thus, if the result of the division is an integer, you'll get it exactly (instead of possibly a value just below, like what you got with binary). But make sure that your inputs are already in decimal.

Objective C - Creating Angles From Current Time

I'm trying to write code to draw a clock on the screen of an iOS device. I need to get the angle of a line (seconds, minutes, hours hands of clock) from the current time. My code accurately grabs the time, but for some reason, all of the angles I receive end up being the same (no matter what time it is).
If it helps, the angle I am constantly receiving is:
-1.5707963267948966
Here is the code I use to get the angles:
secondsTheta = ((seconds/60) * (2 * M_PI)) - (M_PI / 2);
minutesTheta = ((minutes/60) + (seconds/3600)) * (2 * M_PI) - (M_PI / 2);
hoursTheta = ((hours/12) + (minutes/720) + (seconds/43200)) * (2 * M_PI) - (M_PI / 2);
My thought is that something is funky with M_PI, but I don't know what would be...but as I said, the seconds, minutes, and hours variables are correct. They are declared in my header file as ints, and I know that [NSDateComponents seconds](etc) returns an NSInteger, but I don't think that should matter for this basic math.
Since the seconds, minutes, and hours variables are declared as ints the division will not give you the correct values. An int divided by another init will result in an int, what is needed for the result is a float. In order to have the compiler use floating point arithmetic it is necessary that one of the operands be a floating point format number (float).
Example: 10 seconds divided by 60 (10/60) will use integer math and result in 0.
Example: 10.0 seconds divided by 60 (10/60) will use floating point math and result in 0.1.66666667.
Example:
secondsTheta = ((seconds/60.0) * (2 * M_PI)) - (M_PI / 2);
or
secondsTheta = (((float)seconds/60) * (2 * M_PI)) - (M_PI / 2);
Your seconds, minutes and hours are ints. Dividing ints by ints does integer arithmetic and truncates the values, so
seconds/60
will always give you 0. Objective C inherits this behavior from C and this is fairly common behavior among programming languages.

Calculate download percentage in Objective C

I got stuck with a problem that looked pretty easy but i cant make it work.
I'm making a simple download manager for OSX using objective C. As part of the app im trying to calculate the percentage of the current download. im trying to use this code but it wont work for me
long double precent = (bytesDownloaded/downloadSize) * 100;
NSLog(#"precnt %Lf",precent);
NSLog(#"Downloadedbyret: %lld", bytesDownloaded);
The bytesDownloaded and downloadSize are long long.
Can someone please advise,
thanks
To get the correct answer, you must cast the values to long double.
long double precent = ((long double)bytesDownloaded/(long double)downloadSize);
NSLog(#"precnt %Lf",precent);
NSLog(#"Downloadedbyret: %lld", bytesDownloaded);
Is the denominator an int, change it to a floating point? Try:
long double precent = (bytesDownloaded/(downloadSize * 1.0));
NSLog(#"precnt %Lf",precent);
NSLog(#"Downloadedbyret: %lld", bytesDownloaded);
To get % complete you need to multiply by 100.
long double precent = (bytesDownloaded/downloadSize) * 100.0;
if the values bytesDownloaded and downloadSize are int you will need to cast them to a floating point value.
Or if integers multiple the dividend by 100 first:
(bytesDownloaded * 100) / downloadSize;

Objective-C Integer Arithmetic

I'm trying to calculate some numbers in an iPhone application.
int i = 12;
int o = (60 / (i * 50)) * 1000;
I would expect o to be 100 (that's milliseconds) in this example but it equals 0 as displayed by NSLog(#"%d", o).
This also equals 0.
int o = 60 / (i * 50) * 1000;
This equals 250,000, which is straight left-to-right math.
int o = 60 / i * 50 * 1000;
What's flying over my head here?
Thanks,
Nick
In Objective-C / performs integer division on integer arguments, so 4/5 is truncated to 0, 3/2 is truncated to 1, and so on. You probably want to cast some of your numbers to floating-point forms before performing division.
You're also running in to issues with precedence. In the expression
60 / (i * 50) * 1000
the term inside the parentheses is calculated first, so 60 is divided by 600 which produces the result 0. In
60 / i * 50 * 1000
the first operation is to divide 60 by 12 which gives the result 5 and then the multiplications are carried out.
An integer divided by an integer is an integer.
so 60/600 is not 0.1, it is 0.
Cast (or declare) some stuff as float instead.
It's doing integer math. 60 / (12 * 50) is 0.1, truncates to 0.
Should work if you force floating point and then cast back to an integer.
int o = (int)(60.0 / ((double) i / 50.0) * 1000.0;
Probably not really necessary to make everything a double.
Replace:
int o = (60 / (i * 50)) * 1000;
with:
int o = 1200/i;
By order of precedence, the operation:
60 / (12 * 50)
is performed before multiplying by 1000.
This value is less than 1 and is cast to an int, which truncates it to 0. And 0 times anything is 0.
Use a float or first multiply by 1000 to ensure you're not ending up with propagating a 0 in your calculations.
All the operations in your expression are performed in integer arithmetic, meaning that the fractional part of each intermediate result is truncated. This means that if you divide a smaller integer by a larger integer you will always get 0.
To get the result you want you must either make sure the operations are performed in a particular order, or you must use floats. For example the result of
int o = (60.0 / (i * 50.0)) * 1000.0;
should be o = 100.
I think you need to use float here instead of int. It will work the way you want! Will give you answer in decimals as well.

Syntax for rounding up in VB.NET

What is the syntax to round up a decimal leaving two digits after the decimal point?
Example: 2.566666 -> 2.57
If you want regular rounding, you can just use the Math.Round method. If you specifially want to round upwards, you use the Math.Ceiling method:
Dim d As Decimal = 2.566666
Dim r As Decimal = Math.Ceiling(d * 100D) / 100D
Here is how I do it:
Private Function RoundUp(value As Double, decimals As Integer) As Double
Return Math.Ceiling(value * (10 ^ decimals)) / (10 ^ decimals)
End Function
Math.Round is what you're looking for. If you're new to rounding in .NET - you should also look up the difference between AwayFromZero and ToEven rounding. The default of ToEven can sometime take people by surprise.
dim result = Math.Round(2.56666666, 2)
You can use System.Math, specifically Math.Round(), like this:
Math.Round(2.566666, 2)
Math.Round(), as suggested by others, is probably what you want. But the text of your question specifically asked how to "roundup"[sic]. If you always need to round up, regarless of actual value (ie: 2.561111 would still go to 2.57), you can do this:
Math.Ceiling(d * 100)/100D
The basic function for rounding up is Math.Ceiling(d), but the asker specifically wanted to round up after the second decimal place. This would be Math.Ceiling(d * 100) / 100. For example, it may multiply 46.5671 by 100 to get 4656.71, then rounds up to get 4657, then divides by 100 to shift the decimal back 2 places to get 46.57.
I used this way:
Math.Round(d + 0.49D, 2)
Math.Ceiling((14.512555) * 100) / 100
Dot net will give you 14.52. So, you can use above syntax to round the number up for 2 decimal numbers.
I do not understand why people are recommending the incorrect code below:
Dim r As Decimal = Math.Ceiling(d * 100D) / 100D
The correct code to round up should look like this:
Dim r As Double = Math.Ceiling(d)
Math.Ceiling works with data type Double (not Decimal).
The * 100D / 100D is incorrect will break your results for larger numbers.
Math.Ceiling documentation is found here: http://msdn.microsoft.com/en-us/library/zx4t0t48.aspx