Round down floating point conversion in java - java

I have a line in my code much like below:
float rand = (float) Math.random();
Math.random() returns a double that is >=0.0 and <1.0. Unfortunately, the cast above may set rand to 1.0f if the double is too close to 1.0.
Is there a way to cast a double to a float in such a way that when no exact equal value can be found, it always rounds down to the next float value instead of to the nearest float value?
I'm not looking for advice on RNGs, nor work-arounds such as following up with if(rand == 1.0f) rand = 0.0f;. In my case, that solution is a satisfactory way to fix my problem, and it has already been implemented. I am just interest in finding out "proper" solution to this kind of number conversion.

If you only want to round when rand==1.0f, then I second #paxdiablo's answer. However, it sounds like you're okay with always rounding, and simply want to always round down. If so:
float rand = Math.nextDown((float)Math.random());
from the javadoc:
nextDown(float f)
Returns the floating-point value adjacent to f in the direction of negative infinity.
In response to your comment - good point. To avoid that problem, you could simply wrap the statement in a call to Math.abs(), which will have no affect except when the result of nextDown() is negative.
float rand = Math.abs(Math.nextDown((float)Math.random()));

The option I'd suggest would be to use double rather than float.
The only disadvantages I've ever found generally only come into play when you have a large number of them, in that the storage requirements are higher, and this doesn't appear to be the case here.
If you must use float, then the solution you've already tried is probably the best one available. It's a fundamental problem that loss of precision when converting double to float may give you 1.0f.
So coerce the float value to be in your desired range.
However, you don't have to pepper your code with if statements for this, simply provide a float random function that does the grunt work for you:
float frandom() {
float ret = 1.0f;
while (ret == 1.0f)
ret = (float) Math.random();
return ret;
}
or, as per your sample:
float frandom() {
float ret = (float) Math.random();
if (ret == 1.0f)
ret = 0.0f;
return ret;
}
then call it with:
float rand = frandom();
This would be the point where it would be nice for Java (and others) to have the Javascript ability to "inject" code into a type so that you could implement frandom() into the static Math arena. That way you could just use:
float rand = Math.frandom();
But, alas, this is not yet possible (as far as I know, short of recompiling the Java support libraries, which seems a bit of an overkill).
By the way, if you're looking for the maximum float value less than 1, it's 0.99999994 (an exponent multiplier of 2-1 with all mantissa bits set to 1), so you could use that instead of 0.0f in the frandom() function above.
This is gleaned from a handy little tool I wrote some time ago, one that's proven invaluable when fiddling about with IEEE754 floating point values.

Related

Do rounding errors occur also in floats representing integers?

When creating a range of numbers as follows,
float increment = 0.01f;
for (int i = 0; i < 100; i++) {
float value = i * increment;
System.out.println(value);
}
it is clear, that I will end up for some i with values like
0.049999997, which are no exact multiples of 0.01, due to rounding errors.
When I try the same with floats in the range of usual integers, I have never seen the same problem:
float increment = 1.0f; //Still a float but representing an int value
for (int i = 0; i < 100; i++) {
float value = i * increment;
System.out.println(value);
}
One could expect, that this also prints out e.g. 49.999999 instead of 50, which I never saw however.
I am wondering, whether I can rely on that for any value of i and any value of increment, as long as it represents an integer (although its type is float).
And if so, I would be interested in an explanation, why rounding errors can not happen in that case.
Integers in a certain range (about up to one million or so) can be represented exactly as a float. Therefore you don't get rounding errors when you work only with them.
This is because float is based on floating point notation.
In rude words it tries to represent your decimal number as a sum of fractions of power 2.
It means it will try to sum 1/2^n1 + 1/2^n2 + 1/2^n3 .... 1/2^nm until gets closes or exact value that you put.
For example (rude):
0.5 it will represent as 1/2
0.25 it will represent as 1/2²
0.1 it will represent as 1/2^4
but in this case it will mutiply the number by 1.600000023841858 (mantissa) and it will give a number closer but not equal to 1 (1/2^4 x 1.600000023841858 = 0,100000001
Now you can see why after some loops the value changes to nonsense values
For rich detail of how it works read floating points IEEE 754
If you want precision you should use for example a BigDecimal from Java that uses another architecture to represent decimal numbers.
Double has the same problem.
Check this tool to see the repressentation of floating point:
http://www.h-schmidt.net/FloatConverter/IEEE754.html
It doesn't really represent an integer. It's still a float that you're just attempting to add the value 1.0 to. You'll get rounding errors as soon as 1.0 underflows (whenever the exponent gets larger than zero).

Java float not acting correctly [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does (360 / 24) / 60 = 0 … in Java
I am having this problem:
float rate= (115/100);
When I do:
System.out.println(rate);
It gives me 1.0
What... is the problem?
115 and 100 are both integers, so will return an integer.
Try doing this:
float rate = (115f / 100f);
You're performing integer division (which provides an integer result) and then storing it in a float.
You need to use at least one float in the operation for the result to be the proper type:
float rate = 115f / 100;
float rate= (115/100);
Does the following things:
1) Performs integer division of 115 over 100 this yields the value 1.
2) Cast the result from step 1) to a float. This yields the value 1.0
What you want is this:
float rate = 115.0/100;
Or more generally, you want to convert one of the pieces of your division into a float whether that is via casting (float)115/100 or by appending a decimal point to one of the two pieces or by doing this float rate = 115f / 100 is completely up to you and yields the same result.
In order to perform floating-point arithmetic with integers you need to cast at least one of the operands to a float.
Example:
int a = 115;
int b = 100;
float rate = ((float)a)/b;
use float rate= (float)(115.0/100); instead
It is enough to put float rate = 115f / 100;
The problem you have is that your dividend and divisor are declared as integer type.
In mathematic when you divide two integer results only with remainder. And that is what you assign to your rate variable.
So to have the result as you expected, a remainder with fraction (rational numbers). Your dividend or divisor must be declared in a type with precision.
Base two known types with precision are float (Floating point) and double (Double precision).
By default all numbers (integer literals for purists) written in Java code are in type int (Integer). To change that you need to tell the compiler that a number you want to declare should be represent in different type. To do that you need to append a suffix to integer literal.
Literals for decimal types:
float - f or F; 110f;
double - d or D 110D;
Note that when you would like to use the double, type you can also declare it by adding a decimal separator to literal:
double d = 2.;
or
double d = 2.0;
I encourage you to use double type instead of float. Double type is more suitable for most of modern application. Usage of float may cause unexpected results, because of accuracy problem that in single point calculation have bigger impact on result. Good reading about this “What Every Computer Scientist Should Know About Floating-Point Arithmetic”.
In addition on current CPU architecture both float and double have same performance characteristic. So there is not need to sacrifice the accuracy.
A final note about floating point types in is that non of them should be use when we write a financial application. To have valid results in this matter, you should always used [BigDecimal]

Java / Android - equation for rounding up

I am building an android application. In my app, i need to be able to round up a double (42.42 for example) and also get how much i added to the original number in order to round it up. My current code isn't working, and its outputting 0.. Anyway to fix this?
My current code:
float rounded = FloatMath.ceil(val);
double getDecimal = (val - FloatMath.floor(val))*100;
int noDecimal = (int) ((int) 100-getDecimal);
float toadd = (noDecimal/100);
In my code the "rounded" variable is the simpel rounding, and "toadd" should be how much i added to it. For some reason toadd always comes back as 0. Any help?
You're dividing noDecimal by 100. Both are ints, and the result will always be an int. In this case, it's an int between 0 and 1, which will always be truncated to 0.
What's wrong with just getting the number modulo 1 (%1), then getting the ceiling of the original number?
For completeness, you could simply change the last line to preserve the rest of the logic:
float toadd = noDecimal/100.0;
This changes the divisor to a float, and an int divided by a float yields a float.
float toadd = (noDecimal/100);
This will give you 0, as you are dividing smaller integer by larger one..
Try to do like this: -
float toadd = (Float.valueOf(noDecimal)/100);
Also, you don't need to do typecast twice in the below code: -
int noDecimal = (int) ((int) 100-getDecimal);
Just, outer cast is enough: -
int noDecimal = (int) (100-getDecimal);
Edit: - Also, you might want to use BigDecimal for this kind of problems..
Maybe I'm missing something or not getting your intention right, but if you just want to know what you added, why don't just use the difference?
float rounded = FloatMath.ceil(val);
float toadd = rounded-val;
Edit: As mentioned in the comments, this might not always give the absolutely accurate result. But it's the general idea which can be used with BigDecimal, which offers a higher precision.

Math.atan() returning input

I'm having a problem with Math.atan returning the same value as the input.
public double inchToMOA( double in, double range){
double rangeIn = 36*range;
double atan = (in / rangeIn) * -1.0;
double deg = Math.atan(atan);
double moa = deg * 60;
return moa;
}
I had this all in one line, but I broke it down into different variables to see if I could find out why it wasn't working. if in = -10 and range = 300, then atan is about -.00094. The angle should be about -.053 degrees, but math.atan is returning -.00094, the same as the input.
Is my number too small for math.atan?
Inverse tangent is described here:
http://mathworld.wolfram.com/InverseTangent.html
I don't think your argument is the problem here.
You realize, of course, that computer trig functions deal in radians rather than degrees, right?
It might just be. If you look at the strict definition of the tangent function in mathematics what you see if that tan(x) = sin(x)/cos(x) for small values of "x"
lim x->0, sin(x) = x
lim x->0, cos(x) = 1
hence, you could see that lim x->0, tan(x) -> x meaning that it's inverse, arctan, returns the value it is given. As to the numerical accuracy of Math.atan I would think that the authors had gone to great lengths to ensure it's numerical accuracy.
There's nothing wrong with Math.atan. Its value is nearly 1:1 linear, intersecting the origin, for inputs close to zero. So the closer you are to zero the less change from the input there will be.

Java using Mod floats

I am working on an exercise in Java. I am supposed to use / and % to extract digits from a number. The number would be something like 1349.9431. The output would be something like:
1349.9431
1349.943
1349.94
1349.9
I know this is a strange way to do but the lab exercise requires it.
Let's think about what you know. Let say you have the number 12345. What's the result of dividing 12345 by 10? What's the result of taking 12345 mod 10?
Now think about 0.12345. What's the result of multiplying that by 10? What's the result of that mod 10?
The key is in those answers.
if x is your number you should be able to do something like x - x%0.1 to get the 1349.9, then x - x%.0.01 to get 1349.94 and so on. I'm not sure though, doing mod on floats is kind of unusual to begin with, but I think it should work that way.
x - x%10 would definetly get you 1340 and x - x%100 = 1300 for sure.
Well the work will be done in background anyway, so why even bother, just print it.
float dv = 1349.9431f;
System.out.printf("%8.3f %8.2f %8.1f", dv, dv, dv);
Alternatively this could be archived with:
float dv = 1349.9431f;
System.out.println(String.format("%8.3f %8.2f %8.1f", dv, dv, dv));
This is a homework question so doing something the way you would actually do in the real world (i.e. using the format method of String as Margus did) isn't allowed. I can see three constraints on any answer given what is contained in your question (if these aren't actually constraints you need to reword your question!)
Must accept a float as an input (and, if possible, use floats exclusively)
Must use the remainder (%) and division (/) operator
Input float must be able to have four digits before and after the decimal point and still give the correct answer.
Constraint 1. is a total pain because you're going to hit your head on floating point precision quite easily if you have to use a number with four digits before and after the decimal point.
float inputNumber = 1234.5678f;
System.out.println(inputNumber % 0.1);
prints "0.06774902343743147"
casting the input float to a double casuses more headaches:
float one = 1234.5678f;
double two = (double) one;
prints "1234.5677490234375" (note: rounding off the answer will get you 1234.5677, which != 1234.5678)
To be honest, this had me really stumped, I spent way too much time trying to figure out how to get around the precision issue. I couldn't find a way to make this program work for 1234.5678f, but it does work for the asker's value of 1349.9431f.
float input = 1349.9431f;
float inputCopy = input;
int numberOfDecimalPoints = 0;
while(inputCopy != (int) inputCopy)
{
inputCopy = inputCopy * 10;
numberOfDecimalPoints++;
}
double inputDouble = (double) input;
double test = inputDouble * Math.pow(10, numberOfDecimalPoints);
long inputLong = Math.round(test);
System.out.println(input);
for(int divisor = 10; divisor < Math.pow(10, numberOfDecimalPoints); divisor = divisor * 10)
{
long printMe = inputLong - (inputLong % divisor);
System.out.println(printMe / Math.pow(10, numberOfDecimalPoints));
}
Of my three constraints, I've satisfied 1 (kind of), 2 but not 3 as it is highly value-dependent.
I'm very interested to see what other SO people can come up with. If the asker has parsed the instructions correctly, it's a very poor exercise, IMO.

Categories