Objective-C If Statement Comparing Floats not working - iphone

This is literally the weirdest thing I have ever encountered. So, I have a float called ratingDecimal, and I use some conditions to compare it. Here is what the conditions look like:
if (ratingDecimal >= 0.0) {
if (ratingDecimal < 0.3 && ratingDecimal != 0.3) {
ratingDecimal = 0.0;
NSLog(#"bigger or equal to 0 and smaller than 0.3");
}
}
if (ratingDecimal >= 0.3) {
if (ratingDecimal < 0.8 && ratingDecimal != 0.8) {
ratingDecimal = 0.5;
NSLog(#"middle");
}
}
if (ratingDecimal >= 0.8) {
NSLog(#"bigger or equal to 0.8");
ratingDecimal = 1.0;
}
Here is a weird problem. I have set the ratingDecimal to 0.8, the console logs ratingDecimal as:
0.8
but calls:
middle
Which should only be called if ratingDecimal is bigger or equal to 0.3 but smaller than 0.8 and DOES NOT equal to 0.8.
The statement that should be getting called is:
if (ratingDecimal >= 0.8) {
NSLog(#"bigger or equal to 0.8");
ratingDecimal = 1.0;
}
But I do not see
bigger or equal to 0.8
You are probably wondering why my conditions are so tedious and complex, they can be as simple as:
if (ratingDecimal >= 0.3 < 0.8)
They used to be like that but since this has never worked I kept on breaking the statement down and it is STILL acting weird.
Why is this happening!?
Here is an image example:

Your ratingDecimal value is probably something like 0.7999999999999. When printed to the console, something is probably rounding it to 0.8, but the comparison still sees it as less than 0.8.
This is due to the binary nature of floating point numbers. See What Every Computer Scientist Should Know About Floating-Point Arithmetic for extensive information on this.

#Greg gave a good answer. I'd like to point out that you can write that code in a much clearer and simpler fashion:
if (ratingDecimal >= 0.0) {
if (ratingDecimal < 0.3) {
ratingDecimal = 0.0;
NSLog(#"bigger or equal to 0 and smaller than 0.3");
} else if (ratingDecimal < 0.8) {
ratingDecimal = 0.5;
NSLog(#"middle");
} else {
ratingDecimal = 1.0;
NSLog(#"bigger or equal to 0.8");
}
} else {
// negative
}
As an FYI - a line such as:
if (ratingDecimal < 0.3 && ratingDecimal != 0.3) {
doesn't make such sense. If a number is less than 0.3 then it must be unequal to 0.3 so the second check doesn't do anything useful.

you can use functions like roundf() according to your need.

Related

I am trying to make a timer in unity for reload using Time.deltaTime. Anyone know why this isn't working?

Here is the code, I'm not sure why this isn't working. I've done things very simmilar before.
float limit = 1f;
float i = 0f;
if(hasResetReload == true && i < limit)
{
i += Time.deltaTime;
}
else if(i == limit)
{
hasResetReload = false;
anim.SetBool("Reload", false);
}
When you write i += Time.deltaTime;, it will assign a 7 digit long float value to i. Now, when you say i == limit, it will have to match all 7 digits on both float which is almost impossible and never become true. You have to use i >= limit. So, it will become true whenever i become greater than or equal to limit.

for (increase time delay) depending on object count

A math question. I am trying to animate objects sequentially, but I can't figure out formula which will allow me to set a delay smoothly. If I have, lets say, 2 object in my array I want them to animate almost normally with i*0.25 delay, but if I have 25 objects I want them to animate rather quickly. Yes I can try to set manual ratio switching the .count, but I think there should be a nice formula for this?
for (i,object) in objects.enumerated() {
object.animate(withDelay: (i * 0.25) / objects.count)
}
Your best bet is to choose an animation time that will happen EVERY time, no matter the # of variables.
let animateTime = 2 // 2 secs
let animateTimePerObject:Double = animateTime/objects.count
for (i,object) in objects.enumerated() {
object.animate(withDelay: (i * animateTimePerObject)
}
Say there are 10 objects, and you want to animate for 2 seconds. This will set animateTimePerObject = 2/10 = .2 Each item will be delayed by i (whatever position they are at) * the animatetime per object. So in order, 0, 0.2, 0.4, 0.6, 0.8, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2.
Same could be done with 2 objects.
OR you could do a log function that would allow for growth but at a slower rate. Here are some functions you could look at using.
Add this function to create a custom log functionality
func logC(val: Double, forBase base: Double) -> Double {
return log(val)/log(base)
}
for (i,object) in objects.enumerated() {
let delay = i == 0 ? .25 : logC(Double(i)*10, forBase: 10) * 0.25
object.animate(withDelay: delay)
}
This will slow down your 0.25*i rate to a much slower one.
0 -> .25
1 -> Log(20, base: 10) = 1.3 * 0.25 = .325
...
25 -> Log(250, base: 10) = 2.3979 * 0.25 = .6
where it would have been
0 -> .25
1 -> .25 * 2 = .5
25 -> .25 * 25 = 6.25
You can play with the log function as you like, but these are just some ideas. It's not precise as to what kind of algorithm you are looking for.
NOTE: May be syntax issues in there slightly, with the Doubles and Ints but you can adjust! :)
Comparing Log and Sqrt:
func logC(val: Double, forBase base: Double) -> Double {
return log(val)/log(base)
}
for i in 0..<25 {
let delay = i == 0 ? 0.25 : pow(logC(val: Double(i)*10, forBase: 10) * 0.25, log(1/Double(i))) * 0.45
let delay2 = i == 0 ? 0.25 : sqrt(Double(i)) * 0.5
print(delay, delay2)
}
0.25 0.25
0.45 0.5
0.9801911408397829 0.7071067811865476
1.3443747821649137 0.8660254037844386
1.5999258430124579 1.0
1.7853405889097305 1.118033988749895
1.9234257236285595 1.224744871391589
2.0282300761096543 1.3228756555322954
2.1088308307833894 1.4142135623730951
2.1713433790123178 1.5
2.2200343505615683 1.5811388300841898
2.2579686175608598 1.6583123951777
2.2874024254699274 1.7320508075688772
2.3100316733059247 1.8027756377319946
2.32715403828525 1.8708286933869707
2.33977794890637 1.9364916731037085
2.348697701417663 2.0
2.3545463958925756 2.0615528128088303
2.357833976756366 2.1213203435596424
2.358975047645847 2.179449471770337
2.35830952737025 2.23606797749979
2.3561182050020992 2.29128784747792
2.35263460234384 2.345207879911715
2.348054124507179 2.3979157616563596
2.3425411926260447 2.449489742783178
You can go with the function below, which depends on the object count as you specified earlier and if the array will have more objects each animation will be executed with less delay but nonetheless first item's delay will be longer than latter:
for (i,object) in objects.enumerated() {
object.animate(withDelay: ((1/((i+1)*0.5)) * 0.25) / objects.count)
}
There are a lot of parantheses but I hope it will increase readability, also I applied i+1 so you wont have division by zero problem for the first item.
With this formula I hope the delay will diminish gradually and smoothly when your array has large amount of objects.
Note:
If you think delay is too much when there are not much elements in the array (which will lower the "objects.count" number. Try replacing objects.count with (2 * objects.count)
Also if you think the reverse (delay is not much) when there are a lot of elements in the array (which will increase the "objects.count" number. Try replacing objects.count with (objects.count / 2)

Can Time.deltaTime reach 0?

Here is sample of short code
if (timer < 0)
{
timer = cooldown;
}
else if (timer > 0)
{
timer -= Time.deltaTime;
}
else if (timer == 0)
{
print(0);
}
and may be cooldown = 1
My question is easy:
is it possible to reach state timer == 0 ?
I mean theoretically is there possibility of hitting precisely 0 with Time.deltaTime ? I know it sounds stupid considering size of float but still im pretty interested if this scenario could happen.
Delta time can not be zero. Delta time mean the time difference between last frame and current frame. So theoretically it can't be zero. Maybe your timer variable can be but its really low chance. I assume your timer variable is float so when you check if its 0 its actually 0.000000 (something like that). But your timer variable will decrease like 0.969987 , 0.9525292 , ...... , 0.003284598 and after that it will jump to negative values like -0.01333026. When it becomes a negative value you will miss your third if statement.
if (timer <= 0)
{
timer = cooldown;
print(0);
}
else if (timer > 0)
{
timer -= Time.deltaTime;
}
I believe this is a better solution for your case.

iOS alpha value of imageView failing comparison

Here's my code:
#define kDeselected .3
#define kSelected 1
- (void) selectButton:(UIImageView*)iconView{
[iconView setAlpha:kDeselected];
if(iconView.alpha == kDeselected){
[iconView setAlpha:kSelected];
}
else if(iconView.alpha == kSelected){
[iconView setAlpha:kDeselected];
}
}
I'm a pretty advanced programmer but it's beyond me as to why right before the if statement, when I manually went in and ensured that the if statement would result to true, it still doesn't hit it.
It should be noted that when kDeselected = .5, then it works perfectly. When it's .3 however...it doesn't like me.
Try casting your const to a float value as #define kDeselected 0.3f
It might be due to a compiler problem when casting your constant into a type
Try doing
CGFloat deselectedValue = kDeselected;
and see what it's value actually is, and try working with that:
- (void) selectButton:(UIImageView*)iconView{
CGFloat deselectedValue = kDeselected;
[iconView setAlpha:deselectedValue];
if(iconView.alpha == deselectedValue){
[iconView setAlpha:deselectedValue];
}
else if(iconView.alpha == kSelected){
[iconView setAlpha:kDeselected];
}
}
Your other option is to try and define your .3 as #define kDeselected 0.3f, however I doubt it'll make a difference if .5 works
I guess there is some limited precision in the storage of alpha in the iconView. It's probably returning 0.3334. Or thereabouts.
In image editing, it's rare to see an alpha value outside an 8-bit integer range. In fact, I don't think I've ever seen one.
I tried
for (int i = 0; i <100; i++) {
double myAlpha = 0.3 + i * 0.01;
self.view.alpha = myAlpha;
NSLog(#"myAlpha=%30.20f viewAlpha=%30.20f", myAlpha, self.view.alpha);
}
and saw
myAlpha= 0.29999999999999998890 viewAlpha= 0.30000001192092895508
myAlpha= 0.30999999999999999778 viewAlpha= 0.31000000238418579102
myAlpha= 0.32000000000000000666 viewAlpha= 0.31999999284744262695
myAlpha= 0.32999999999999996003 viewAlpha= 0.33000001311302185059
myAlpha= 0.33999999999999996891 viewAlpha= 0.34000000357627868652
so expecting the returned value of alpha to be anything other than an approximation looks like wishful thinking!

Square collision detection iPhone

I have this game where i need to know if the ball has hit a wall on the side (to bounce back on the x-axis) or on the top (to bounce back on the y-axis, like a bounce on the ground). They work fine individually, but when I uncomment both of them, it dosen't work. (I think this is because the code is 'overlapping'?). Anyway, here is the code, and any help is fantastic:
if (CGRectIntersectsRect(guy.frame, wall_01.frame)) {
if (guy.frame.origin.y+guy.frame.size.height >= wall_01.frame.origin.y && guy.frame.origin.y <= wall_01.frame.origin.y+wall_01.frame.size.height) {
iJump *= kRestitution;
}
if (guy.frame.origin.x+guy.frame.size.width >= wall_01.frame.origin.x && guy.frame.origin.x <= wall_01.frame.origin.x+wall_01.frame.size.width) {
jJump *= kRestitution;
}
}
assuming wall is on the left side and the y increases from top to bottom
CGFloat leftWall = someXPosition;
CGFloat ground = someYPosition;
CGFloat ballLeft = CGRectGetMinX(guy.frame);
CGFloat ballRight = CGRectGetMaxX(guy.frame);
CGFloat ballBottom = CGRectGetMaxY(guy.frame);
if (ballLeft <= leftwall && ballBot >= ground){
//ball hit corner ?
} else if (ballLeft <= leftWall){
//passed or touched wall
} else if (ballBot >= ground){
//passed or touched ground
}