Im working on a small calculation app and I'm using a formula I created in PHP and now trying to translate to Objective-C however, the power operator is not clear to me.
Im looking at the following code:
float value = ((((x)*i)/12)/(1-(1+i/12)^-((x*12))))-i;
The power operator is non existent in Objective-C.
How should I apply the power operator in Objective-C and could some assist me by telling me where it should be?
(Too many parentheses! You don't need parentheses around x or (x*12), for instance.)
There is no power operator. The standard function powf() will do the job, however (pow() if you wanted a double result):
float value = x * i / 12 / (1 - powf(1 + i / 12, -12 * x)) - i;
^ is the bitwise XOR operator both in C (and so in Objective-C as well) and in PHP.
To perform a power operator use the C pow (which returns a double) or powf (which returns a float) functions
float result = powf(5, 2); // => 25
Your expression will then become (stripping away all the redundant parenthesis and leaving some for readability) :
float value = (x*i/12) / (1 - powf(1 + i/12, -x*12)) - i;
Related
i am trying to make a recursive function, that can rewrite a float to an continued fraction. I am getting an error messange that i dont understand
it seems like it can't storage certain numbers binary and how do i compare then. Thats my current theory.
condition 'cfa_reg != -1' not met
let rec float2cfrac (x : float) : int list =
if x - floor x = 0.0 then
[int x]
else
[int x] # float2cfrac (1.0/(x - floor x))
printfn "%A" (float2cfrac 3.245)// list
When I run your code. I get a stack overflow.
That means that your condition x - floor x = 0.0 is never met.
Equality with floating point numbers is a tricky thing as there is always a small precision error involved in all calculations. Never use equality, instead calculate until the difference is less than an acceptable error:
abs(x - floor x) < 0.0000000001
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.
To convert 32-bit unsigned to signed integer one could use:
function convert(n)
if n >= 2 ^ 31 then
return n - 2 ^ 32
end
return n
end
Is it possible to do it without that comparison?
PS: This is Lua, hence I cannot "cast" as in C.
Maybe you could do it with bit operations. In Smalltalk that would be:
^self - (2*(self bitAnd: 16r80000000))
Apparently bitops are not native in Lua, but various bit library seem available, see http://lua-users.org/wiki/BitwiseOperators
Once you find appropriate bitand function, that would be something like
return n - bitand(n,MAXINT)*2
Not in plain Lua. You could of course optimize the exponentiation and the if-statement away by writing:
local MAXINT, SUBT = math.pow(2, 31), math.pow(2, 32)
function convert(n)
-- Like C's ternary operator
return (n >= MAXINT and n - SUBT) or n
end
I do not know if optimizing the if-statement away will help the interpreter much; not for LuaJIT, I think; but probably for plain Lua?
If you really want to avoid the comparison, go for C, e.g. (untested code!):
int convert(lua_State *L)
{
lua_pushinteger(L, (int) ((unsigned int) luaL_checklong(L, 1)));
return 1;
}
However, stack overhead will probably defeat the purpose.
Any specific reason for the micro-optimization?
Edit: I've been thinking about this, and it is actually possible in plain Lua:
local DIV, SUBT = math.pow(2, 31) + 1, math.pow(2, 32)
-- n MUST be an integer!
function convert(n)
-- the math.floor() evaluates to 0 for integers 0 through 2^31;
-- else it is 1 and SUBT is subtracted.
return n - (math.floor(n / DIV) * SUBT)
end
I'm unsure whether it will improve performance; the division would have to be faster than the conditional jump.
Technically however, this answers the question and avoids the comparison.
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));
Could anyone explain to me why this keeps returning 0 when it should return a value of 42? it works on paper so i know the math is right I'm just wondering as to why it isn't translating across?
int a = 60;
int b = 120;
int c = 85;
int progress;
progress = ((c-a)/(b-a))*100;
NSLog(#"Progess = %d %%",progress);
It's because your math is all using integers.
In particular, your inner expression is calculating 25 / 60, which in integer math is zero.
In effect you have over-parenthesised your expression, and the resulting order of evaluation is causing integer rounding problems.
It would have worked fine if you had just written the formula so:
progress = 100 * (c - a) / (b - a);
because the 100 * (c - a) would first evaluate to 2500, and would then be divided by 60 to give 41.
Alternative, if any one (or more) of your variables a, b, or c were a float (or cast thereto) the equation would also work.
That's because an expression in which either operand is a float will cause the other (integer) operand to be promoted to a float, too, at which point the result of the expression will also be a float.
c - a will give you 25
b - a will give you 60
Since a, b, and c are all integers, meaning they can't be decimals. Therefore, by doing (c-a)/(b-a), you will get 0, instead of 0.41666666 because in integer division, anything after the decimal point will get cut off, leaving the number before the decimal point.
To make it work the way you wanted it to, you should try casting (c-a) and (b-a) to either double or float:
progress = ((float)(c-a) / (float)(b-a)) * 100;
or
progress = ((double)(c-a) / (double)(b-a)) * 100;
a,b and c are ints. When you calculate ((c-a)/(b-a)), the result is also an int; the real value is a decimal (0.42), but an int can't take a decimal number, so it rounds to 0, which is multiplied by 100 to get 0.
Because (c - a) / (b - a) is computed using integer math.
To fix, cast to a float before dividing:
progress = (int)((((float)(c - a)) / ((float)(b - a))) * 100);