How to explain the strange results for while loop with floating point in swift - while-loop

I have tested while loop below and don’t understand the result.
var x: Float = 0.0
var counter = 0
while x < 1.41
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) // 1.5
How is it possible to have the result x = 1.5 for the used while condition where x < 14.1 ? How to explain this result?
Update:
and one more. Why the results are different for Double and Float ?
var x: Double = -0.5
var counter = 0
while x < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 16
print (x)//1.1
var x: Float = -0.5
var counter = 0
while x < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
Update 2
and another one. Why there is no difference for < and <= conditions. Does it mean that usage of <= has no sense for floating point ?
var x: Double = 0.0
var counter = 0
while x < 1.5
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) //1.5
var x: Double = 0.0
var counter = 0
while x <= 1.5
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) //1.5

What else would you expect? The loop is executed 15 times. On the 14th time, x is 1.4 and so you add another 0.1, making it 1.5.
If you expect the loop to terminate at 1.4, you should increment x before checking the while condition, not after that.
If you expect the loop to terminate on 1.41, your increment is wrong and you should do
x += 0.01
instead, making it 141 iterations.
As for the second question, I am aware that Float should not be used for monetary calculations and such due to its lack of precision. However, I trusted Double so far, and the while loop in run 15 actually claims the Double value to be less than 1.0 while it is reported to be 1.0. We have got a precision problem here, as we can see if we substract x from 1.0:
print(1.0-x)
which returns: 1.11022302462516e-16
At the same time, Float seems to be unprecise in the other direction. In the last run, it is a little bigger than 0.9 (0.9 + 5.96046e-08), making it bigger than 10 in the following run.
The reason why Double and Float are wrong in different directions is just a matter of how the values are stored, and the result will be different depending on the number. For example, with 2.0 both actual values are bigger: Double by 4.440892..e-16 and Float by 2.38419e-07. For 3.0 Double is bigger by 1.33226e-15 and Float smaller by 7.1525e-07.
The same problems occur using x.isLess(than: 1.0), but this method is the basis for the < operator as of https://developer.apple.com/reference/swift/floatingpoint/1849403-isless
isLessThanOrEqualTo(1.0), on the other hand, seems to work reliably as expected.
This answer is pretty much a question itself by now, so I'm curious if anyone has an in-depth explanation of this...
Update
The more I think about it, the less of a Swift problem it is. Basically, you have that problem in all floating point calculations, because they are never precise. Both Float and Double are not precise, Double is just twice as accurate. However, this means that comparisons like == are useless with floating point values unless they are both rounded. Therefore, good advice in loops like those of yours with a known precision (in your case one decimal) would be to round to that precision before doing any kind of comparison. For example, this would fix the loop:
var x: Double = -0.5
var counter = 0
while (round(x * 1000) / 1000) < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
var x: Float = -0.5
var counter = 0
while (round(x * 1000) / 1000) < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0

Related

How to shorten this code or make it more efficient?

I want to know if there is any more efficient/shorter way to give the same result.
The function get_action_strength(action) returns a boolean if the key is pressed,
Thanks.
var degValue = 0
if (Input.get_action_strength("move_forward")):
degValue = 0
if (Input.get_action_strength("move_right")):
degValue += -45
if (Input.get_action_strength("move_left")):
degValue += 45
elif (Input.get_action_strength("move_backward")):
degValue = 180
if (Input.get_action_strength("move_right")):
degValue -= -45
if (Input.get_action_strength("move_left")):
degValue -= 45
else:
if (Input.get_action_strength("move_right")):
degValue = -90
if (Input.get_action_strength("move_left")):
degValue = 90
The function get_action_strength(action) returns a boolean if the key is pressed
No, it doesn't. get_action_strength returns float. You can use that to your advantage.
You can do this:
var x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
Furthermore, atan2 will return 0 if the parameters are 0. That is one of the benefit of using atan2 instead of atan: You don't have to worry about a division by 0. Thus, you don't need to check if x and y are not 0, just use them.
By the way, y comes before x in atan2.
One more thing, there is a rad2deg function, if you have radians and want degrees:
var x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
var degValue = rad2deg(atan2(y, x))
If you really want, you can inline the variables, and it would be a one-liner.
Ah, sorry, I may have misunderstood. You want it to be discrete, right? You want ceil:
var x = ceil(Input.get_action_strength("move_right")) - ceil(Input.get_action_strength("move_left"))
var y = ceil(Input.get_action_strength("move_forward")) - ceil(Input.get_action_strength("move_backward"))
var degValue = rad2deg(atan2(y, x))
Second branch of if's can be changed to smth like that:
degValue += -45 * int(Input.get_action_strength("move_right")) + 45 * int(Input.get_action_strength("move_left"))
When the value is False and you convert it to int, it becomes 0, and the multiply result is 0. So only one of the values is added.
Also, if the question is tagged 'python', why are you declaring variable with 'var' keyword? =)
You can use vectors and compute the angle from its components:
motion_vec_x = 0
motion_vec_y = 0
if (Input.get_action_strength("move_forward")):
motion_vec_y = 1
if (Input.get_action_strength("move_backward")):
motion_vec_y = -1
if (Input.get_action_strength("move_left")):
motion_vec_x = -1
if (Input.get_action_strength("move_right")):
motion_vec_x = 1
degValue = None
if abs(motion_vec_x) > 0 or abs(motion_vec_y) > 0:
degValue = np.arctan2(motion_vec_x, motion_vec_y) / np.pi * 180
print(degValue
This will yield (depending on the arctan2 implementation) 0° for up, negative degrees for a vector tilted to the left and positive values for the vector tilted to the right. Pointing straight down is going to be 180°. You will easily be able to convert this to any angle values you need and deem fit.

Integer casting within arithmetic expressions in Kotlin

In the following Kotlin code example I expected the value of parameter i to be equal to 0, such as is the case for the parameter k. The IDE reports all i, j and k as Int. Is it a bug or do I need to readjust my understanding of Kotlin casting inside expressions? For example, is there a rule to always promote/cast to Double inside expressions involving division, but not multiplication?
fun main() {
//Kotlin 1.3.61
val x = 100 * 1.0/100 //Double
val i = 100 * 1/100 //Int
val j = 1/100 //Int
val k = 100 * j //Int
println(x) //1.0
println(i) //1
println(j) //0
println(k) //0
}
I expected the value of parameter i to be equal to 0
The output is arithmetically right: 100 * 1 / 100 = (100 * 1) / 100 = 100 / 100 = 1 / 1 = 1
, such as is the case for the parameter k.
The value j is 0, so anything multiplied by it will be zero, as in case of k.
is there a rule to always promote/cast to Double inside expressions
involving division, but not multiplication?
If you divide integers, you will get an integer back. If one of the numbers is a Double, the result will be a Double:
val x = 100 * 1.0/100 //Double because 1.0 is a Double
--
There is actually already a discussion on kotlin forum to your problem here:
Mathematically speaking the current behaviour is correct.
This is called integer devision and results in the quotient as an
answer

Processing: conditional to test for variable change

My question pertains to the environment of Processing 2.0.
I need to write a conditional (or set of conditionals) in void draw() that tests if the variable x has increased by 1 or decreased by 1 and adjust the variable y depending on the increase/decrease in x. For example if x decreases 1, y should increase by 10, and if x increases by 1 y should decrease by 10. How would I accomplish this?
The most obvious answer is to try to think of y as a multiple of x plus maybe an offset? So if you have your x going up and down every time you enter the draw() method you should do y = x * 10; or y = 400 + x * 10 if you have an offset (int this case 400) of some sorts...
If you absolutely have to do it like that, then the way is to store the previous value of x and check each at each draw() call. So create a new variable int prevX and in your draw() method do:
y = y + (x-prevX) * 10;
or
int diff = x - prevX;
if(diff == -1) y = y - 10;
else if (diff == 1) y = y + 10;

Randomize float using arc4random?

I have a float and I am trying to get a random number between 1.5 - 2. I have seen tutorials on the web but all of them are doing the randomization for 0 to a number instead of 1.5 in my case. I know it is possible but I have been scratching my head on how to actually accomplish this. Can anyone help me?
Edit1: I found the following method on the web but I do not want all these decimals places. I only want things like 5.2 or 7.4 etc...
How would I adjust this method to do that?
-(float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
{
int startVal = num1*10000;
int endVal = num2*10000;
int randomValue = startVal + (arc4random() % (endVal - startVal));
float a = randomValue;
return (a / 10000.0);
}
Edit2: Ok so now my method is like this:
-(float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
{
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
return val;
}
Will this produce numbers like 1.624566 etc..? Because I only want say 1.5,1.6,1.7,1.8,1.9, and 2.0.
You can just produce a random float from 0 to 0.5 and add 1.5.
EDIT:
You're on the right track. I would use the maximum random value possible as your divisor in order to get the smallest intervals you can between possible values, rather than this arbitrary division by 10,000 thing you have going on. So, define the maximum value of arc4random() as a macro (I just found this online):
#define ARC4RANDOM_MAX 0x100000000
Then to get a value between 1.5 and 2.0:
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
return val;
This will also give you double precision if you want it (just replace float with double.)
EDIT AGAIN:
Yes, of course this will give you values with more than one decimal place. If you want only one, just produce a random integer from 15 to 20 and divide by 10. Or you could just hack off the extra places afterward:
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
int val1 = val * 10;
float val2= (float)val1 / 10.0f;
return val2;
arc4random is a 32-bit generator. It generates Uint32's. The maximum value of arc4random() is UINT_MAX. (Do not use ULONG_MAX!)
The simplest way to do this is:
// Generates a random float between 0 and 1
inline float randFloat()
{
return (float)arc4random() / UINT_MAX ;
}
// Generates a random float between imin and imax
inline float randFloat( float imin, float imax )
{
return imin + (imax-imin)*randFloat() ;
}
// between low and (high-1)
inline float randInt( int low, int high )
{
return low + arc4random() % (high-low) ; // Do not talk to me
// about "modulo bias" unless you're writing a casino generator
// or if the "range" between high and low is around 1 million.
}
This should work for you:
float mon_rand() {
const u_int32_t r = arc4random();
const double Min = 1.5;
if (0 != r) {
const double rUInt32Max = 1.0 / UINT32_MAX;
const double dr = (double)r;
/* 0...1 */
const double nr = dr * rUInt32Max;
/* 0...0.5 */
const double h = nr * 0.5;
const double result = Min + h;
return (float)result;
}
else {
return (float)Min;
}
}
That was the simplest I could think of, when I had the same "problem" and it worked for me:
// For values from 0.0 to 1.0
float n;
n = (float)((arc4random() % 11) * 0.1);
And in your case, from 1.5 to 2.0:
float n;
n = (float)((arc4random() % 6) * 0.1);
n += 15 * 0.1;
For anybody who wants more digits:
If you just want float, instead of arc4random(3) it would be easier if you use rand48(3):
// Seed (only once)
srand48(arc4random()); // or time(NULL) as seed
double x = drand48();
The drand48() and erand48() functions return non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0 , 1.0].
Taken from this answer.

Making change using Objective-C

I just recently started studying Objective-C (or programming for that matter) and am stuck at a simple program.
I'm trying to create change in quarters, dimes, nickels, and pennies but noticed that the solution I came up with would give random value to nickels or pennies.
Ex.
Change for 25 would come out to "The change is 1 quarter, 0 dime, -1881139893 nickels, and 4096 pennis"
Ex2.
Change for 30 would come out to "The change is 1 quarter, 0 dime, 1 nickels, and 4096 pennis"
What can I add/change to fix this behavior?
Also, is there any better solution then having to run 4 different if statements?
Thanks!
Here's my code below:
int orig, q, d, n, p;
NSLog(#"Give money to make change");
scanf("%i", &orig);
if(orig >= 25) {
q = orig/25;
orig -= q*25;
}
if(orig >= 10 && orig < 25) {
d = orig/10;
orig -= d*10;
}
if(orig >= 5 && orig < 10) {
n = orig/5;
orig -= n*5;
}
if(orig >= 1 && orig < 5) {
p = orig;
}
NSLog(#"The change is %i quarter, %i dime, %i nickels, and %i pennis", q, d, n, p);
You don't initialize your variables to start with, so they all start with random values, then in your code, in the case where there's no pennys, you never set p to anything, so it retains its initial random value, which you then see in your output. You can fix it by initializing your variables at the start.
int orig=0, q=0, d=0, n=0, p=0;
You should make use of modulus instead. I don't want to ruin your learning experience so this is an example of how you can use modulus to calculate days, hours, minutes and seconds for time given in seconds only.
int x = 1123123;
int seconds = x % 60;
x /= 60;
int minutes = x % 60;
x /= 60;
int hours = x % 24;
x /= 24;
int days = x;
Now apply it to your problem :)