strange number of repetitions in for loop - java

I wrote this little program to calculate pi.
While playing with the code and trying to find the most exact result, I found a point where my computer couldn't calalculate a result. It could do 33554430 repetitions within seconds, but if i increased the for loop to 33554431 it didn't output anything.
So is 33554430 a special number?
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
}

You are getting and endless loop, because during the comparison i <= 33554431, the int value 33554431 is promoted to a float value which is "too precise" for float and will actually equal to 33554432.
Then, when you try to increase the value by +2, the float just isn't precise enough to increment from the value 33554432. To illustrate my point:
float f = 33554432;
System.out.println(f); //33554432
f += 2;
System.out.println(f); //33554432
So the value f doesn't increase due to its precision limitation. If you'd increase it by, say 11, you'd get 33554444 (and not 33554443) as that is the closest number expressible with that precision.
So is 33554430 a special number?
Sort of, not 33554430 but rather 33554432. First "special number" for float is 16777217, which is the first positive integer that cannot be represented as a float (equals 16777216 as float). So, if you'd increment your i variable by 1, this is the number you'd get stuck on. Now, since you are incrementing by 2, the number you get stuck on is 16777216 * 2 = 33554432.

public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554431; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
if( i > 33554410) System.out.println(i);
}
pi *= 4;
System.out.println(pi);
System.out.println((float)33554431);
System.out.println((float)33554432);
System.out.println((float)33554434);
}
}
You compare float with int in for loop. When you convert 33554431 (it's int value) to float you get 3.3554432E7.
It's about accuracy, precision. When you run:
System.out.println((float)33554431); // -> 3.3554432E7
System.out.println((float)33554432); // -> 3.3554432E7
System.out.println((float)33554434); // -> 3.3554432E7
All 3 prints 3.3554432E7, it means that when you increase float value of 33554432 by 2, you get 3.3554432E7, exactly this same value, and your loop runs forever.

Your loop increments by 2 each time.
2 * 33554430 = 67108860
2 ^ 26 = 67108864
Maybe Java stores floating point numbers in a 32bit system by using 26bits for the mantissa and 6 bits for the exponent?

This version works for both. It's the float loop variable causing problems:
public static void main(String[] args){
float pi=0;
int sign=1;
for(int i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/(float)i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
Probably this is due this issue:
The finite nonzero values of any floating-point value set can all be
expressed in the form s · m · 2(e - N + 1), where s is +1 or -1, m is
a positive integer less than 2N, and e is an integer between Emin =
-(2K-1-2) and Emax = 2K-1-1, inclusive, and where N and K are parameters that depend on the value set.

Related

Why does this return Infinity? (Java)

Im trying to find the result of 1/1 + 1/4 + 1/9 + 1/16 + 1/25 ...
These is the lines I wrote that give the result Infinity:
public class BaselProblem {
public static void main(String[] args) {
int testLimit = 100000;
double sum = 0;
for (int i = 1; i<testLimit; i++)
{
sum = sum + 1.0/(i*i);
}
System.out.println(sum);
}
}
Changing 1.0/(i*i) to 1/(1.0*i*i) gives the correct result 1.6449240667982423. Why is it that only the 2nd form work but not the 1st?
Also, because (i*i) > 1, then 1.0/(i*i) should be < 1, so how can it leads to in Infinity?
Because your testLimit as well as your i are defined as int. Since you put the expression i*i in parentheses, it will be calculated first, and will try to find the multiple of two integers - which will reach overflow pretty quickly and reset to zero.
Specifically, when i reaches 2¹⁶, i*i will be 2³². This means 1 followed by 32 zeros in binary, of which, only the 32 zeros are kept, which means zero. (Thanks #templatetypedef).
Therefore, you'll have a number divided by zero, which is infinity.
Change your loop declaration so that i is double. Or multiply by a double (1.0) on the left hand of i*i. This will cause the expression to be changed into double before multiplying by the second i.
Java integer have a maximum value of 2,147,483,647. You're eventually surpassing that maximum with the integer that results from i*i.
If you do 1.0*i*i, you're converting the result to a double which can hold a maximum value of 1.79769313486231570E+308.
Your maximum value for i*i will be 10,000,000 which a double can hold, but an integer can't.

Generate a Double in the Double domain

According to this question, to create a Double number in a given range, you can use:
Random r = new Random();
double randomValue = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
I'm trying to generate a double number in the double domain [Double.MIN_VALUE, Double.MAX_VALUE] using the same code mentioned above:
package test;
import java.util.Random;
public class Main {
public static void main(String[] args) {
double lower = Double.MIN_VALUE;
double upper = Double.MAX_VALUE;
Random rand = new Random();
for (int i = 0; i < 200; i++) {
double a = lower + (upper - lower) * rand.nextDouble();
System.out.println(a);
}
}
}
However, I'm getting just positive numbers even after many iterations:
1.436326007111308E308
2.7068601271148073E307
1.266896721067985E308
8.273233207049513E306
1.3338832492644417E308
8.584898485464862E307
1.260909190772451E308
1.5511066198317899E307
1.2083062753983258E308
2.449979496663398E307
7.333729592027637E307
7.832069948910962E307
8.493365260900201E307
5.158907971928131E307
3.126231202546818E307
1.3576316635349233E308
1.0991793636673692E308
6.991662398870649E307
My question is: How to generate a double number in the double range?
The results are not what you expected, because MIN_VALUE is the smallest possible positive double value. The smallest possible double value is -Double.MAX_VALUE (note the minus sign).
But you can not simply use lower = -Double.MAX_VALUE, because then, the difference will not be representable as a double, and will overflow.
A first idea would be something like
double d = random.nextDouble() * Double.MAX_VALUE;
if (random.nextBoolean()) d = -d;
to cover the full possible range.
EDIT: A (possibly minor) aside: The proposed method should cover the negative double values as well, and should be correct in the sense that each possible value appears either in its positive or in its negative form with equal probability. However, it will not be able to return the value Double.MAX_VALUE (because the value returned by Random#nextDouble() is strictly smaller than 1.0). But based on the implementation of nextDouble, there anyhow may be double values that will never appear in the output.
Double.MIN_VALUE is the smallest positive value that you can represent as a double.
it is not the largest negative number. that would be -Double.MAX_VALUE
As I said in the comment and others have also said, MIN_VALUE is positive. But even if you use -Double.MAX_VALUE, your computation will overflow double precision when computing upper - lower because the result will be two times the maximum double! One way around this is:
val = Random.nextDouble();
return (val < 0.5) ? (-2 * val) * Double.MAX_VALUE : (2 * (val - 0.5)) * Double.MAX_VALUE;

Convert a float to int

Android Studio 0.5.2
Hello,
I have a random float value that I want to convert to an int.
The float could have a random number between -9.4182062E-9 to 9.593071E-8.
I just want to get the positive int number so if the number is negative i.e. -5.5115866E-8 it should just return 5. I have used the Math.abs for this.
I have tried the following:
int accel = (int)Math.abs(randomAccel);
However, accel keeps giving me a zero no matter what value randomAccel is.
Many thanks for any suggestions,
Your negative number -5.485747E-5 finish by E-5 meaning that it is -0.0000548574
So the absolute value is 0.0000548574.
So Math.abs(-0.0000548574) is 0.0000548574
(int)0.0000548574 is 0
result is 0
Are your sure your code is responding 0 no matter the value of random? Check the number you are trying to convert.
You should unit test your code with your values.
Your random number range has very small a magnitude (negative exponents) - importantly it is less than +/-1. When float is cast to int, all fractional parts are truncated, thus every number in your range, after setting the sign to positive, will result in 0 if cast to int.
It seems like you want to ignore the exponent of your numbers. One way to do that would be:
int accel = Integer.parseInt(String.valueOf(randomAccel).replaceAll("-?(\\d+).*", "$1"));
int accel = (int)Math.abs(randomAccel);
This line performs 3 steps
Get the absolute value of randomAccel
Cast the value to an int (floating point numbers are truncated)
Assign the int value to accel
Now lets look what happens when the input is in the range [-9.4182062E-9,9.593071E-
8] (By the way -5.485747E-5 is not in this range.)
Input value -9.4E-9 = -0.0000000094
1. -9.4E-9 converted to 9.4E-9
2. 9.4E-9 cast to int, fractional part is removed. Value is 0
3. 0 is assigned to `accel`
If you just want to most significant digit, you could multiply by 10^8 and see if that value is greater than 0, if it is then trucate, else multiply by 10 then truncate:
int accel = 0;
r = Math.abs( randomAccel ) * 100000000;
if( r >= 10 ) {/* error out of range */}
else if( r > 0 ) accel = (int)r;
else
{
r *= 10;
accel = (int)r;
}
import static java.lang.Math.*;
Convert part:
double input =-5.485747E-5; //for example
double tmp = abs(input);
tmp *= pow(10, abs(floor(log10(tmp))));
int out = (int) tmp;
System.out.println(out);
output:
5

double takes the value NaN after 0/0

I have this class that works on pixels of a sequence of images
private int makeRSR(int x, int y)
{
double bRed = 0;double bGreen = 0; double bBlue = 0;
for(int k: sequence.keySet())
{
BufferedImage img = sequence.get(k);
for(int i=0; i<iteration; i++){
for(int j=0;j<spray_int; j++){
int dist= ((int)(dis_int*Math.random()));
double theta=((int)(361*Math.random())) ;
double inc_x=dist * Math.cos((theta*(Math.PI/180)));
double inc_y=dist * Math.sin((theta*(Math.PI/180)));
int row=Math.abs((int)(inc_y+y));
int column=Math.abs((int)(inc_x+x));
if(row<1 || column<1 || row>altI-1 || column>largI-1){
row=Math.abs((int) ((altI-1)*Math.random()));
column=Math.abs((int) ((largI-1)*Math.random()));
}
Color c = new Color(img.getRGB(column,row));
red.add(c.getRed());
green.add(c.getGreen());
blue.add(c.getBlue());
}
Color c = new Color(img.getRGB(x,y));
red.add(c.getRed());
green.add(c.getGreen());
blue.add(c.getBlue());
double maxR=max(red);
double maxG=max(green);
double maxB=max(blue);
bRed += ((((double)c.getRed()) / (maxR))*255.00);
bGreen += ((((double)c.getGreen()) / (maxG))*255.00);
bBlue += ((((double)c.getBlue()) / (maxB))*255.00);
red.clear();green.clear();blue.clear();
}
}
redValue=0;greenValue=0;blueValue=0;
redValue= (int) (bRed/(iteration*(sequence.size())));
greenValue= (int) (bGreen/(iteration*(sequence.size())));
blueValue=(int) (bBlue/(iteration*(sequence.size())));
bRed=0.0;bGreen=0.0;bBlue=0.0;
return new Color(redValue,greenValue,blueValue).getRGB();
}
the problem is that sometimes c.getRed() and maxR are both 0 (same for the other channels) and so bRed loses its content and take value NaN, and it never change. Is there an error, something I missed, or do I have to prevent the 0/0 by adding a check?
Thanks, Bye
Since 0/0 is an undefined number you need to decide how do you want do treat it.
Find out why you get both 0 in current and max red values and prevent it.
Set result of division to 0 (or any number you decide to get the expected result) if both c.getRed() and maxR are 0.
Because dividing by zero is an error, it results in NaN, which stands for Not a Number. Subsequent operations involving NaN will also result in NaN, that's why it's value never changes afterwards.
You should explicitly check for zero divident before division to prevent division by zero.

Generate random numbers between two numbers

public class TestSample {
public static void main(String[] args) {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
double ran = Math.random();
}
}
I don't want to use Random r = new Random(); class. Is there any other way to generate random numbers. I am just struck with what logic could be applied to generate random numbers between two numbers.
It's really easy... you only need to figure out which is the minimum value and what is the difference between the two numbers (let's call it diff). Then, you can scale the Math.random value (between 0 and 1) by multiplying by diff (now its range is between 0 and diff). Then, if you add the minimum value, your range is between min and min + diff (which is the other value)
int min = min(a,b);
int max = max(a,b);
int diff = max - min;
int result = min + diff * Math.random();
Consider using this code:
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
double ran = Math.random();
double random;
if(a < b)
random = (b-a)*ran + a;
else
random = (a-b)*ran + b;
This will work for a >= 0 and b >= 0 if you consider using negative number the logic sligtly changes
If you are expecting a double result, the simplest approach is
int a =
int b =
double result = (a-b)*Math.random() + b;
It doesn't matter which is greater as you get the same distribution.
However, if you want a random integer between 'a' and 'b' is a bit more complex.
int a =
int b =
int result = Math.floor((Math.abs(a-b)+1) * Math.random()) + Math.min(a, b);
The reason the result is different is that a random double between 0 and 1 will be just less than 1 i.e. [0.0, 1.0) However a random integer between 1 and 6 usually includes 1, 2, 3, 4, 5, 6 equally. As a decimal this is the round down of [0.0 ... 7.0)
You may get white noise from your microphone, and take any number from there. After that you may take any number from the given data, and do with it what you want. The example of getting data from the microphone can be found here.

Categories

Resources