Java to map a range of float values to graphical display - java

I want to take a range of float values (subject) that change and map them on to a static range of colours 0 - 255 for displaying on the screen.
The subject range of values start with the float being a minimum of 0.056582272 to the largest 0.34371486
when running calculation changes overtime to a minimum of 0.0791025 to the largest 4.5757337
If I map them using
number / 255 * largest
which in code is
thecol=elements[x][y][subject]*255/largest;
You see the colours at the beginning when I pop them on the screen, then at the end but nothing in between.

You did not factor in the minimum of the range for your calculation.
float rangeSize = largest - smallest;
float mappedTo0to1 = (value - smallest) / rangeSize; // Map to range 0 - 1.
int mappedResult = (int) (mappedTo0to1 * 255); // Map to range you want. (0 - 255).
The trick with verifying these kind of functions is to look at the lowest and highest input values possible.

Related

Convert RGB values to binary to decimal

I have the following java code, which takes three double values (between 0 and 1) of the colors RGB and converts them to decimal format. I understood how the first 8 bit save color x, the second 8 bit color y ... and also how to get the decimal value from the resulting binary. what i dont understand 100% is why we multiply with 255 (i know 128+64+32+16+8+4+2+1). What exactly do we get from multiplying the double value with 255. is it a value which can be stored in 8 bit? And why dont we use 256 (possible amount of one color)?
public final double getR() {
return (1 - cyan);
}
public final double getG() {
return (1 - magenta);
}
public final double getB() {
return (1 - yellow);
}
/**
* Gets the rgb color in one integer.
*
* #return an integer containing the red component in bits 16-23, the green component in bits 8-15
* and the blue component in bits 0-7. Bits 24-32 are zero.
*/
public int getRGB() {
int r = (int) Math.round(getB() * 255);
r |= (int) Math.round(getR() * 255) << 16;
r |= (int) Math.round(getG() * 255) << 8;
return r;
}
Thanks
You need the conversion from double because you cannot store the double value into 8 bit.
Your double values are between 0.0 and 1.0. You can see them as the proportion of color used (e.g. 0.33333333 in yellow means that one-third of the possible yellow is used). As you can see such a double can have many decimal places, which means we need a lot of memory (64-bit) to store such a color.
Your function now tries to store the double value into only 8 bit (256 values). As we said the double value can be seen as a portion (between 0 and 1) and the function calculates the same for 8 bit (between 0 and 255). This can simply be done by multiplying the double value with 255. For the example with yellow (0.33333333 of yellow is used) it is: 0.33333333 * 255 = 84,99999915. The meaning is still the same 84,99999915 yellow parts of 255 yellow parts are used, which is still a third.
In order to get a compressed version of this number, it is rounded to the next integer value. In our example, this is 85, which is really close to the actual portion, but we save a lot of memory.
It makes also sense for the lowest double value 0.0, which is converted to the lowest int value 0. The highest double value 1.0 is converted to 255 (highest 8-bit number).
In conclusion, we convert a double (64-bit) into an only 8-bit number, which has the same proportion of the color, but it is not as accurate.
Edit: As there is also a confusion with the 255: 8 bit can store 256 values (0 to 255). If you can choose 256 as a color value somewhere they use the range 1-256 without 0. Essentially it is the same one shifted by 1.

How to convert a float scale to long scale?

I have two scales,one is x-value scale,with float values which starts from minimum x value and ends at maximum x value.I call these values as min_x and max_x.
I have another scale with long value which starts from 0 and ends at maximum time value,i call it max_tim value.
how do i convert a float xvalue into corresponding long time value?
I have tried something on android studio but i am getting incorrect values.
private long max_tim,tim;
private float min_x,max_x,x_val;
tim=((long)((x_val-min_x)/(max_x-min_x)))*max_tim;
I have got correct values of tim for max_x and min_x but not for the values in between.I think i have correct logic but think its faulty typecasting.Please help me out.
float range = max_x - min_x; // get the absolute range of the first scale
float offset = x_val - min_x; // normalize the value on the first scale to the absolute range
tim = (long)((offset*max_tim)/range); // convert to the new scale, which is already in absolute values
For example, if your x-value scale is in farenheit and ranges from 32.0 - 212.0. And your "long scale" is in centigrade from 0-100. And you wanted to convert 50 degrees Farenheit to centigrade
range = 212-32; // 180
offset = 50-32; // 18
tim = (18*100)/180 = 10;
50°F == 10° C

Java, random number and sololearn challenges

How come? I thought that "+1" is the lowest number it can generate... This is the question:
"(int) Math.random()*(65535 + 1) returns a random number between:
Between 0 and 65535. <- answer
This is a question from a sololearn challenge.
The documentation of method Math.random() says:
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
It's obvious - mathematically expressed, the generated interval is <0, 1). It means, the generated number will never reach 1.0 but maximally a number a bit below (ex. 0.99). Since you multiply it with 65535, it will never reach 65535. That's why you have to add +1.
I recommend you to use the class Random and it's method nextInt(int bound) which does:
Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive)
Therefore:
Random random = new Random();
int integer = random.nextInt(65536); // 65535 + 1 because the number is exclusive
The way you have the code right now:
(int) Math.random()*(65535 + 1)
You will always get 0.
The Math.random() method generates a number in the range [0, 1).
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
When you multiply that number by n, it has a range of [0, n). Casting it to int truncates any decimal portion of the number, making that number 0, and anything multiplied with 0 is 0. The cast occurs first because it's a higher precedence than multiplication.
Let's add parentheses so the cast occurs after the multiplication.
(int) (Math.random()*(65535 + 1))
When you multiply the truncated number by n, it has a range of [0, n). Casting it to int after the multiplication truncates any decimal portion of the number, making the range of integers 0 through (n - 1).
If you add 1 after multiplying and casting, then the lowest number it could generate would be 1. The range before adding would be 0 through 65534, after adding it would be 1 through 65535.
(int) (Math.random()*65535) + 1
How come? I thought that "+1" is the lowest number it can generate...
That is because the +1 was placed within the brackets. See below:
(int) Math.random()*(65535 + 1) //is equivalent to
(int) Math.random()*(65536) //which is equivalent to
(int) 0.0 to number < 1.0 *(65536) //which gives you a range of..
(int) (0 * 65536) to (0.999.. * 65536) //which gives you..
(int) 0 to 65535.34464.. //converted to int gives you
0 to 65535
If you want the minimum random number to be at least 1. Add it after the random operation is done:
(int) (Math.random()*65535) + 1

How to clamp a value from 0 to infinite to a value from 0 to 1?

I have a program in Java that generates a float value aggressiveness that can be from 0 to infinite. What I need to do is that the higher this float is, the higher there are chances the program fires a function attackPawn().
I already found out that I need the function Math.random(), which gives a random value between 0 and 1. If Math.random() is lower than aggressiveness transformed into a float between 0 and 1, I call the function attackPawn().
But now I am stuck, I can't figure out how I can transform aggressiveness from 0 to infinite to a float which is from 0 to 1, 1 meaning "infinite" aggressiveness and 0 meaning absence of anger.
Any ideas or math equation?
You want a monotonic function that maps [0...infinity] to [0..1]. There are many options:
y=Math.atan(x)/(Math.PI/2);
y=x/(1+x);
y=1-Math.exp(-x);
There are more. And each of those functions can be scaled arbitrarily, given a positive constant k>0:
y=Math.atan(k*x)/(Math.PI/2);
y=x/(k+x);
y=1-Math.exp(-k*x);
There is an infinite number of options. Just pick one that suits your needs.
It is possible to map [0,infinity) to [0,1), but this won't be linear. An example function would be:
y = tan(x * pi / 2);
The problem with this function is that you can't make a correct computer program from that since it is not possible (or easy) to first compute a real big number like 10^5000 and map it down to [0,1).
But a better solution would be to change your definition to something like that:
0 = no aggression
1 = maximum aggression
With this you don't have to map the numbers
Try something like this:
// aggressiveness is a float with a value between 0 and Float.MAX_VALUE or a value of Float.POSITIVE_INFINITY
if (aggressiveness == Float.POSITIVE_INFINITY) {
aggressiveness = 1f;
} else {
aggressiveness = aggressiveness / Float.MAX_VALUE;
}
// aggressiveness is now between 0 and 1 (inclusive)
Though Double class supports infinite value double d=Double.POSITIVE_INFINITY but i dont think you can use it for your arithmatic purpose. Better you define a maximum value and treat it as infinity.
double Min=0;
double Max= Double.MAX_VALUE;
double aggresiveness= Min + (Math.random() * ((Max - Min) + 1));
ps: you can also take aggresiveness as long or int if you don't want it be a double
Try to transform aggressiveness with a function like:
public float function(float aggressiveness) {
if(aggressiveness > 0F) {
return 1 - (1 / aggressiveness);
}
return 0F;
}
This will map your value to the range of [0, 1);

Randomly generating floats spanning the whole spectrum of valid floats

As part of random testing, I'm looking to generate random floats spanning the whole spectrum of valid floats (but excluding +/- infinity and NaN). I want very, very large numbers and minuscule numbers, both positive and negative.
Here's what I'm doing:
Random r = new Random();
float random_value = (r.nextFloat() - 0.5f) * Float.MAX_VALUE;
This seems like it should in theory work, but it only generates very large values. (ie. in the range of 1037 – 1038, positive and negative)
Any suggestions?
Your code should create uniformly distributed float values, that is, a uniform distribution in a purely mathematical sense. However, most of these values will be in the 1037-1038 range, simply because there are more mathematical values in that range than in the lower, everyday value range. In the real domain, there are 10 times as many values in the range 1037-1038 as 1036-1037, 10 times as many values in the range 1036-1037 as 1035-1036, and so on, so it's no surprise that just about all of them are of extremely large magnitude.
What I think you want is a completely random float value, with a range only in the valid float domain. Because a float is specified by an exponent and a mantissa, the limiting factor as to how many values are available in a given range is limited by the precision, not how many mathematical values are available. Specifically, there are precisely the same number of float values between a and b as there are between 2 * a and 2 * b, provided all values are within the float domain.
There is a one-to-one correspondence between all possible int values and all possible float values (including infinities and NaN), because both primitive types are represented by 32 bits.
Choose a random int value, across all possible int values, positive, 0, and negative, and convert the bit representation of the int to the corresponding bit representation of the float you want. You'll have to choose a random long and downcast to int. If you randomly get an infinity or an NaN, try again.
Random rnd = new Random();
float randomFloat = 0.0f;
do {
// downcast will cover negative int value range.
int randomInt = (int) rnd.nextLong(1L << 32);
float randomFloat = Float.intBitsToFloat(randomInt);
// Discard infinities and NaNs.
} while (randomFloat == Float.NEGATIVE_INFINITY ||
randomFloat == Float.POSITIVE_INFINITY ||
Float.isNaN(randomFloat));
You can get an uniform distribution by generating your floats using bits instead of arithmetic.
This could be an option:
public static float randomFloat() {
// Generate a random integer. These are uniform over the 32 bit words
Random r = new Random();
int intBits = r.nextInt();
// Make a float from the integer's bits
float f = Float.intBitsToFloat(intBits);
// Handle non-numeric cases
if (Float.isInfinite(f) || Float.isNaN(f)) {
// Only happens ~ 1/250 times
return randomFloat();
} else {
return f;
}
}
You are probably hitting precision issues. Try doing the multiplication at double precision and then casting down to a float afterwards.
i.e.
float random_value = (float)((r.nextDouble() - 0.5) * Float.MAX_VALUE);
Firstly you want to generate a random float between -1 and 1. To do this:
Random r = new Random();
float random_value = r.nextFloat() * 2 - 1
and then scale that:
Random r = new Random();
float random_value = (r.nextFloat() * 2 - 1) * Float.MAX_VALUE

Categories