Lets say, I have the following:
float x= ...
float y = ...
What I like to do is just compare them whether x is greater than y or not. I am not interested in their equality.
My question is, should I take into account precision when just performing a > or a < check on floating point values? Am I correct to assume that precision is only taken into account for equality checks?
Since you already have two floats, named x and y, and if there hasn't been any casting before, you can easily use ">" and "<" for comparison. However, let's say if you had two doubles d1 and d2 with d1 > d2 and you cast them to f1 and f2, respectively, you might get f1 == f2 because of precision problems.
There is already a wheel you don't need to invent:
if (Float.compare(x, y) < 0)
// x is less than y
All float values have the same precision as each other.
It really depends on where those two floats came from. If there was roundoff earlier in their computation, then if the accumulated roundoff is large enough to exceed the difference between the "ideal" answers, you may not get the results you expect for any of the comparison values.
As a general rule, any comparison of floats must be considered fuzzy. If you must do it, you are responsible for understanding the sources of roundoff error and deciding whether you care about it and how you want to handle it if so. It's usually better to avoid comparing floats entirely unless your algorithm absolutely requires that you do so... and if you must, to make sure that a "close but not quite" comparison will not break your program. You may be able to restructure the formulas and order of computation to reduce loss of precision. Going up to double will reduce the accumulated error but is not a complete solution.
If you must compare, and the comparison is important, don't use floats. If you need absolute precision of floating-like numbers, use an infinite-precision math package like bignums or a rational-numbers implementation and accept the performance cost. Or switch to scaled integers -- which also round off, but round off in a way that makes more sense to humans.
This is a difficult question. The answer really depends on how you got those numbers.
First, you need to understand that floating point numbers ARE precise, but that they don't necessarily represent the number that you thought they did. Floating point types in typical programming language represent a finite subset of the infinite set of Real numbers. So if you have an arbitrary real number the chances are that you cannot represent it precisely using a float or double type. In fact ...
The only Real numbers that can be represented exactly as float or
double values have the form
mantissa * power(2, exponent)
where "mantissa" and "exponent" are integers in prescribed ranges.
And the corollary is that most "decimal" numbers don't have an exact float or double representation either.
So in fact, we end up with something like this:
true_value = floating_point_value + delta,
where "delta" is the error; i.e. the small (or not so small) difference between the true value and the float or double value.
Next, when you perform a calculation using floating point values, there are cases where the exact result cannot be represented as a floating point value. An obvious example is:
1.0f / 3.0f
for which the true value is 0.33333... recurring, which is not representable in any finite base 2 (or base 10!) floating point representation. Instead what happens is that a result is produced by rounding to the nearest float or double value ... introducing more error.
As you perform more and more calculations, the errors can potentially grow ... or stay stable ... depending on the sequence of operations that are performed. (There's a branch of mathematics that deals with this: Numerical Analysis.)
So back to your questions:
"Should I take into account precision when just performing a > or a < check on floating point values?"
It depends on how you got those floating point values, and what you know about the "delta" values relative to the true Real values they nominally represent.
If there are no errors (i.e. delta < the smallest representable difference for the value), then you can safely compare using ==, < or >.
If there are possible errors, then you need to take account of those errors ... if the semantic of the comparison are intended to couched in terms of the (nominal) true values. Furthermore, you need to have a credible estimate of the "delta" (the accumulated error) when you code the comparison.
In short, there is no simple (correct) answer ...
"Am I correct to assume that precision is only taken into account for equality checks? "
In fact precision is not "taken into account" in any of the comparison operators. These operators treat the operands as precise values, and compare them accordingly. It is up to your code to take account of precision issues, based on your error estimates for the preceding calculations.
If you have estimates for the deltas, then a mathematically sound < comparison would be something like this:
// Assume true_v1 = v1 +- delta_v1 ... (delta_v1 is a non-negative constant)
if (v1 + delta_v1 < v2 - delta_v2) {
// true_v1 is less than true_v2
}
and so on ...
Related
I know that for primitive floating point types (floats and doubles), you're not supposed to compare them directly via ==. But what if you're using the wrapper class for double? Will something like
Double a = 5.05;
Double b = 5.05;
boolean test = a.equals(b);
compare the two values properly?
You need to fully understand the reason for why == comparison is a bad idea. Without understanding, you're just fumbling in the dark.
Let's talk about how computers (and doubles) work.
Imagine you enter a room; it has 3 lightswitches, otherwise it is bare. You will enter the room, you can fiddle with the switches, but then you have to leave. I enter the room later and can look at the switches.
How much information can you convey?
The answer is: You can convey 8 different states: DDD, DDU, DUD, DUU, UDD, UDU, UUD, and UUU. That's it.
Computers work exactly like this when they store a double. Except instead of 3 switches, you get 64 switches. That means 2^64 different states you can convey with a single double, and that's a ton of states: That's a 19 digit number.
But it's still a finite amount of states, and that's problematic: There are an infinite amount of numbers between 0 and 1. Let alone between -infinity and +infinity, which double dares to cover. How do you store one of an infinite infinity of choices when you only get to represent 2^64 states? That 19-digit number starts to look pretty small when it's tasked to differentiate from an infinite infinity of possibilities, doesn't it?
The answer, of course, is that this is completely impossible.
So doubles don't actually work like that. Instead, someone took some effort and hung up a gigantic numerline, from minus infinite to plus infinite, in a big room, and threw 2^64 darts at this line. The numbers they landed on are the 'blessed numbers' - these are representable by a double value. That does mean there are an infinite amount of numbers between any 2 darts that therefore are not representable. The darts aren't quite random: The closer you are to 0, the denser the darts. Once you get beyond about 2^52 or so, the distance between 2 darts exceeds 1.0 even.
Here's a trivial example of a non-representable number: 0.3. Amazing, isn't it? Something that simple. It means a computer literally cannot calculate 0.1 + 0.2 using double. So what happens when you try? The rules state that the result of any calculation is always silently rounded to the nearest blessed number.
And therein lies the rub: You can run the math:
double x = 0.1 + 0.2;
and later do:
double y = 0.9 - 0.8 + 0.15 + 0.05;
and us humans would immediately notice that x and y are naturally identical. But not so for computers - because of that silent rounding to the nearest blessed number, it's possible that x is 0.29999999999999999785, and y is 0.300000000000000000012.
Thus we get to four crucial aspects when using double (or float which is just about worse in every fashion, don't ever use those):
If you need absolute precision, don't use them at all.
When printing them, always round them down. System.out.println does this out of the box, but you should really use .printf("%.5f") or similar: Pick the # of digits you need.
Be aware that the errors will compound, and it gets worse as you are further away from 1.0.
Do not ever compare with ==, instead always use a delta-compare: The notion of "lets consider the 2 numbers equal if they are within 0.0000000001 of each other".
There is no universal magic delta value; it depends on your precision needs, how far you away from 1.0, etc. Therefore, just asking the computer: Hey, just figure this stuff out I just wanna know if these 2 doubles are equal is impossible. The only definition available that doesn't require your input as to 'how close' they can be, is the notion of sheer perfection: They are equal only if they are precisely identical. This definition would fail you in that trivial example above. It makes not one iota of difference if you use Double.equals instead of double == double, or any other utility class for that matter.
So, no, Double.equals is not suitable. You will have to compare Math.abs(d1 - d2) < epsilon, where epsilon is your choice. Mostly, if equality matters at all you're already doing it wrong and shouldn't be using double in the first place.
NB: When representing money, you don't want unpredictable rounding, so never use doubles for these. Instead figure out what the atomic banking unit is (dollarcents, eurocents, yen, satoshis for bitcoin, etc), and store that as a long. You store $4.52 and long x = 452;, not as double x = 4.52;.
I have this problem from the book 'Crack the Coding Interview'.
Given two lines on a Cartesian plane, determine whether the two lines would intersect.`
Here is the solution:
public class Line {
static double epsilon = 0.000001;
public double slope;
public double yintercept;
public Line(double s, double y) {
slope = s;
yintercept = y;
}
public boolean intersect(Line line2) {
return Math.abs(slope - line2.slope) > epsilon ||
Math.abs(yintercept - line2.yintercept) < epsilon;
}
}
Why doesnt it have the simple solution that if the slopes are not same, then they will intersect. Why the epsilon and the y intercept.
In the Suggestions it says that
Don’t assume that the slope and y-intercept are integers. Understand limitations of floating point representations. Never check for equality with ==.
The “solution” is wrong.
Implicit in this “solution” is a notion that the arguments that have been passed are inaccurate, that, before intersect is called, the values have been subject to computations that may produce results with rounding errors. Because there are errors in the values, numbers that would be equal if calculated exactly are unequal. To recognize these as equal, this “solution” accepts as equal some values that are actually unequal.
One flaw in this reasoning is that the intersect routine has no knowledge of how large the errors may be and therefore has no basis for knowing what value of epsilon it should use. The ideal value might be zero, or it might be a million. The value that is used, 1e-5, has no basis in any engineering principle given the information provided. More than that, there is no basis for using an absolute error, as this code does. Depending on circumstances, the proper tolerance to use might be a relative error, an error denominated in ULPs, or some other technique. There is simply no reason to believe that this code will return true when passed arguments that ideally would represent intersecting lines but that have been calculated in some unknown way.
Another flaw is that the routine falsely accepts as equal values that are not equal. The routine will report as not intersecting many lines that do intersect. This code has not solved the problem of the routine returning the wrong answer; it has only changed the cases for which wrong answers are returned, and it may well have greatly increased the number of wrong answers.
First because the simple solution that if the slopes are not the same they will intersect is not complete. They could have the same slope and intercept and would therefore be identical.
The epsilon as the suggestion says is because the number representation in computers is not exact. According to the IEEE-standard a double has about 15 precise calculated digits therefore slope and intercept can have a rounding error due to previous calculations and therefore a simple check with == could yield that they are not identical while they just differ by a rounding error.
Why doesnt it have the simple solution that if the slopes are not
same, then they will intersect. Why the epsilon and the y intercept.
The solution takes in consideration the approximation errors due to floating-point arithmetic.
Because of floating point numbers doesn't represent all possible real numbers, but a relative small subset (more dense in [-1,+1] interval), it's common when you have to deal with floating points arithmetic use a threshold to perform equality checks.
The epsilon valure represent a threshold under which 2 different floating-point values would be considered equals.
Underneath it all, numbers are all converted to binary when they are processed. It is not possible to represent most floating point numbers as an exact binary (because they would be an infinite series of 1s and 0s), and so approximations are made, by truncating the binary sequence. For example, the floating point number 0.1 (ie: one tenth) is not representable as an exact binary number, rather, it is represented by an approximation which looks like 0.000110011... Truncation of this binary number causes potential rounding errors, and so the exact equality "==" could cause a false response, when in fact it is this rounding error which is giving the fake negative. Introducing an epsilon attempts to avoid these errors by saying "anything below this number we consider to be zero". See the "fractions in binary" section of wikipedia to read more.
Is there ever a case where a comparison (equals()) between two floating point values would return false if you compare them as DOUBLE but return true if you compare them as FLOAT?
I'm writing some procedure, as part of my group project, to compare two numeric values of any given types. There're 4 types I'd have to deal with altogether : double, float, int and long. So I'd like to group double and float into one function, that is, I'd just cast any float to double and do the comparison.
Would this lead to any incorrect results?
Thanks.
If you're converting doubles to floats and the difference between them is beyond the precision of the float type, you can run into trouble.
For example, say you have the two double values:
9.876543210
9.876543211
and that the precision of a float was only six decimal digits. That would mean that both float values would be 9.87654, hence equal, even though the double values themselves are not equal.
However, if you're talking about floats being cast to doubles, then identical floats should give you identical doubles. If the floats are different, the extra precision will ensure the doubles are distinct as well.
As long as you are not mixing promoted floats and natively calculated doubles in your comparison you should be ok, but take care:
Comparing floats (or doubles) for equality is difficult - see this lengthy but excellent discussion.
Here are some highlights:
You can't use ==, because of problems with the limited precision of floating point formats
float(0.1) and double(0.1) are different values (0.100000001490116119384765625 and 0.1000000000000000055511151231257827021181583404541015625) respectively. In your case, this means that comparing two floats (by converting to double) will probably be ok, but be careful if you want to compare a float with a double.
It's common to use an epsilon or small value to make a relative comparison with (floats a and b are considered equal if a - b < epsilon). In C, float.h defines FLT_EPSILON for exactly this purpose. However, this type of comparison doesn't work where a and b are both very small, or both very large.
You can address this by using a scaled-relative-to-the-sizes-of-a-and-b epsilon, but this breaks down in some cases (like comparisons to zero).
You can compare the integer representations of the floating point numbers to find out how many representable floats there are between them. This is what Java's Float.equals() does. This is called the ULP difference, for "Units in Last Place" difference. It's generally good, but also breaks down when comparing against zero.
The article concludes:
Know what you’re doing
There is no silver bullet. You have to choose wisely.
If you are comparing against zero, then relative epsilons and ULPs based comparisons are usually meaningless. You’ll need to use an absolute epsilon, whose value might be some small multiple of FLT_EPSILON and the inputs to your calculation. Maybe.
If you are comparing against a non-zero number then relative epsilons or ULPs based comparisons are probably what you want. You’ll probably want some small multiple of FLT_EPSILON for your relative epsilon, or some small number of ULPs. An absolute epsilon could be used if you knew exactly what number you were comparing against.
If you are comparing two arbitrary numbers that could be zero or non-zero then you need the kitchen sink. Good luck and God speed.
So, to answer your question:
If you are downgrading doubles to floats, then you might lose precision, and incorrectly report two different doubles as equal (as paxdiablo points out.)
If you are upgrading identical floats to double, then the added precision won't be a problem unless you are comparing a float with a double (Say you'd got 1.234 in float, and you only had 4 decimal digits of accuracy, then the double 1.2345 MIGHT represent the same value as the float. In this case you'd probably be better to do the comparison at the precision of the float, or more generally, at the error level of the most inaccurate representation in the comparison).
If you know the number you'll be comparing with, you can follow the advice quoted above.
If you're comparing arbitrary numbers (which could be zero or non-zero), there's no way to compare them correctly in all cases - pick one comparison and know its limitations.
A couple of practical considerations (since this sounds like it's for an assignment):
The epsilon comparison mentioned by most is probably fine (but include a discussion of the limitations in the write up). If you're ever planning to compare doubles to floats, try to do it in float, but if not, try to do all comparisons in double. Even better, just use doubles everywhere.
If you want to totally ace the assignment, include a write-up of the issues when comparing floats and the rationale for why you chose any particular comparison method.
I don't understand why you're doing this at all. The == operator already caters for all possible types on both sides, with extensive rules on type coercion and widening which are already specified in the relevant language standards. All you have to do is use it.
I'm perhaps not answering the OP's question but rather responding to some more or less fuzzy advice which require clarifications.
Comparing two floating point values for equality is absolutely possible and can be done. If the type is single or double precision is often of less importance.
Having said that the steps leading up to the comparison itself require great care and a thorough understanding of floating-point dos and don'ts, whys and why nots.
Consider the following C statements:
result = a * b / c;
result = (a * b) / c;
result = a * (b / c);
In most naive floating-point programming they are seen as "equivalent" i e producing the "same" result. In the real world of floating-point they may be. Or actually, the first two are equivalent (as the second follows C evaluation rules, i e operators of same priority left to right). The third may or may not be equivalent to the first twp.
Why is this?
"a * b / c" or "b / c * a" may cause the "inexact" exception i e an intermediate or the final result (or both) is (are) not exact(ly representable in floating point format). If this is the case the results will be more or less subtly different. This may or may not lead to the end results being amenable to an equality comparison. Being aware of this and single-stepping through operations one at a time - noting intermediate results - will allow the patient programmer to "beat the system" i e construct a quality floating-point comparison for practically any situation.
For everyone else, passing over the equality comparison for floating-poiny numbers is good, solid advice.
It's really a bit ironic because most programmers know that integer math results in predictable truncations in various situations. When it comes to floating-point almost everyone is more or less thunderstruck that results are not exact. Go figure.
You should be okay to make that cast as long as the equality test involves a delta.
For example: abs((double) floatVal1 - (double) floatVal2) < .000001 should work.
Edit in response to the question change
No you would not. The above still stands.
For the comparison between float f and double d, you can calculate the difference of f and d. If abs(f-d) is less than some threshold, you can think of the equality holds. These threshold could be either absolute or relative as your application requirement. There are some good solutions Here. And I hope it helpful.
Would I ever get an incorrect result if I promote 2 floats to
double and do a 64bit comparison rather than a 32bit comparison?
No.
If you start with two floats, which could be float variables (float x = foo();) or float constants (1.234234234f) then you can compare them directly, of course. If you convert them to double and then compare them then the results will be identical.
This works because double is a super-set of float. That is, every value that can be stored in a float can be stored in a double. The range of the exponent and mantissa are both increased. There are billions of values that can be stored in a double but not in a float, but there are zero values that can be stored in a float but not a double.
As discussed in my float comparison article it can be tricky to do a meaningful comparison between float or double values, because rounding errors may have crept in. But, converting both numbers from float to double doesn't not change this. All of the mentions of epsilons (which are often but not always needed) are completely orthogonal to the question.
On the other hand, comparing a float to a double is madness. 1.1 (a double) is not equal to 1.1f (a float) because 1.1 cannot be exactly represented in either.
I expected the following code to produce: "Both are equal", but I got "Both are NOT equal":
float a=1.3f;
double b=1.3;
if(a==b)
{
System.out.println("Both are equal");
}
else{
System.out.println("Both are NOT equal");
}
What is the reason for this?
It's because the closest float value to 1.3 isn't the same as the closest double value to 1.3. Neither value will be exactly 1.3 - that can't be represented exactly in a non-recurring binary representation.
To give a different understanding of why this happens, suppose we had two decimal floating point types - decimal5 and decimal10, where the number represents the number of significant digits. Now suppose we tried to assign the value of "a third" to both of them. You'd end up with
decimal5 oneThird = 0.33333
decimal10 oneThird = 0.3333333333
Clearly those values aren't equal. It's exactly the same thing here, just with different bases involved.
However if you restrict the values to the less-precise type, you'll find they are equal in this particular case:
double d = 1.3d;
float f = 1.3f;
System.out.println((float) d == f); // Prints true
That's not guaranteed to be the case, however. Sometimes the approximation from the decimal literal to the double representation, and then the approximation of that value to the float representation, ends up being less accurate than the straight decimal to float approximation. One example of this 1.0000001788139343 (thanks to stephentyrone for finding this example).
Somewaht more safely, you can do the comparison between doubles, but use a float literal in the original assignment:
double d = 1.3f;
float f = 1.3f;
System.out.println(d == f); // Prints true
In the latter case, it's a bit like saying:
decimal10 oneThird = 0.3333300000
However, as pointed out in the comments, you almost certainly shouldn't be comparing floating point values with ==. It's almost never the right thing to do, because of precisely this sort of thing. Usually if you want to compare two values you do it with some sort of "fuzzy" equality comparison, checking whether the two numbers are "close enough" for your purposes. See the Java Traps: double page for more information.
If you really need to check for absolute equality, that usually indicates that you should be using a different numeric format in the first place - for instance, for financial data you should probably be using BigDecimal.
A float is a single precision floating point number. A double is a double precision floating point number. More details here: http://www.concentric.net/~Ttwang/tech/javafloat.htm
Note: It is a bad idea to check exact equality for floating point numbers. Most of the time, you want to do a comparison based on a delta or tolerance value.
For example:
float a = 1.3f;
double b = 1.3;
float delta = 0.000001f;
if (Math.abs(a - b) < delta)
{
System.out.println("Close enough!");
}
else
{
System.out.println("Not very close!");
}
Some numbers can't be represented exactly in floating point (e.g. 0.01) so you might get unexpected results when you compare for equality.
Read this article.
The above article clearly illustrates with examples your scenario while using double and float types.
float a=1.3f;
double b=1.3;
At this point you have two variables containing binary approximations to the Real number 1.3. The first approximation is accurate to about 7 decimal digits, and the second one is accurate to about 15 decimal digits.
if(a==b) {
The expression a==b is evaluate in two stages. First the value of a is converted from a float to a double by padding the binary representation. The result is still only accurate to about 7 decimal digits as a representation of the Real 1.3. Next you compare the two different approximations. Since they are different, the result of a==b is false.
There are two lessons to learn:
Floating point (and double) literals are almost always approximations; e.g. actual number that corresponds to the literal 1.3f is not exactly equal to the Real number 1.3.
Every time you do a floating point computation, errors creep in. These errors tend to build up. So when you are comparing floating points / double numbers it is usually a mistake to use a simple "==", "<", etcetera. Instead you should use |a - b| < delta where delta is chosen appropriately. (And figuring out what is an appropriate delta is not always straight-forward either.)
You should have taken that course in Numerical Analysis :-)
Never check for equality between floating point numbers. Specifically, to answer your question, the number 1.3 is hard to represent as a binary floating point and the double and float representations are different.
The problem is that Java (and alas .NET as well) is inconsistent about whether a float value represents a single precise numeric quantity or a range of quantities. If a float is considered to represents an exact numeric quantity of the form Mant * 2^Exp, where Mant is an integer 0 to 2^25 and Exp is an integer), then an attempt to cast any number not of that form to float should throw an exception. If it's considered to represent "the locus of numbers for which some particular representation in the above form has been deemed likely to be the best", then a double-to-float cast would be correct even for double values not of the above form [casting the double that best represents a quantity to a float will almost always yield the float that best represents that quantity, though in some corner cases (e.g. numeric quantities in the range 8888888.500000000001 to 8888888.500000000932) the float which is chosen may be a few parts per trillion worse than the best possible float representation of the actual numeric quantity].
To use an analogy, suppose two people each have a ten-centimeter-long object and they measure it. Bob uses an expensive set of calibers and determines that his object is 3.937008" long. Joe uses a tape measure and determines that his object is 3 15/16" long. Are the objects the same size? If one converts Joe's measurement to millionths of an inch (3.937500") the measurements will appear different, but one instead converts Bob's measurement to the nearest 1/256" fraction, they will appear equal. Although the former comparison might seem more "precise", the latter is apt to be more meaningful. Joe's measurement if 3 15/16" doesn't really mean 3.937500"--it means "a distance which, using a tape measure, is indistinguishable from 3 15/16". And 3.937008" is, like the size of Joe's object, a distance which using a tape measure would be indistinguishable from 3 15/16.
Unfortunately, even though it would be more meaningful to compare the measurements using the lower precision, Java's floating-point-comparison rules assume that a float represents a single precise numeric quantity, and performs comparisons on that basis. While there are some cases where this is useful (e.g. knowing whether the particular double produced by casting some value to float and back to double would match the starting value), in general direct equality comparisons between float and double are not meaningful. Even though Java does not require it, one should always cast the operands of a floating-point equality comparison to be the same type. The semantics that result from casting the double to float before the comparison are different from those of casting the float to double, and the behavior Java picks by default (cast the float to double) is often semantically wrong.
Actually neither float nor double can store 1.3. I am not kidding. Watch this video carefully.
https://www.youtube.com/watch?v=RtHKwsXuRkk&index=50&list=PL6pxHmHF3F5JPdnEqKALRMgogwYc2szp1
Do we need to be careful when comparing a double value against zero?
if ( someAmount <= 0){
.....
}
If you want to be really careful you can test whether it is within some epsilon of zero with something like
double epsilon = 0.0000001;
if ( f <= ( 0 - epsilon ) ) { .. }
else if ( f >= ( 0 + epsilon ) ) { .. }
else { /* f "equals" zero */ }
Or you can simply round your doubles to some specified precision before branching on them.
For some interesting details about comparing error in floating point numbers, here is an article by Bruce Dawson.
For equality: (i.e. == or !=) yes.
For the other comparative operators (<, >, <=, >=), it depends whether you are about the edge cases, e.g. whether < is equivalent to <=, which is another case of equality. If you don't care about the edge cases, it usually doesn't matter, though it depends where your input numbers come from and how they are used.
If you are expecting (3.0/10.0) <= 0.3 to evaluate as true (it may not if floating point error causes 3.0/10.0 to evaluate to a number slightly greater than 0.3 like 0.300000000001), and your program will behave badly if it evaluates as false -- that's an edge case, and you need to be careful.
Good numerical algorithms should almost never depend on equality and edge cases. If I have an algorithm which takes as an input 'x' which is any number between 0 and 1, in general it shouldn't matter whether 0 < x < 1 or 0 <= x <= 1. There are exceptions, though: you have to be careful when evaluating functions with branch points or singularities.
If I have an intermediate quantity y and I am expecting y >= 0, and I evaluate sqrt(y), then I have to be certain that floating-point errors do not cause y to be a very small negative number and the sqrt() function to throw an error. (Assuming this is a situation where complex numbers are not involved.) If I'm not sure about the numerical error, I would probably evaluate sqrt(max(y,0)) instead.
For expressions like 1/y or log(y), in a practical sense it doesn't matter whether y is zero (in which case you get a singularity error) or y is a number very near zero (in which case you'll get a very large number out, whose magnitude is very sensitive to the value of y) -- both cases are "bad" from a numerical standpoint, and I need to reevaluate what it is I'm trying to do, and what behavior I'm looking for when y values are in the neighborhood of zero.
Depending on how your someAmount is computed, you may expect some odd behaviour with float/doubles
Basically, converting numeric data to their binary representation using float / doubles is error prone, because some numbers cannot be represented with a mantis/exponent.
For some details about this you can read this small article
You should consider using java.lang.Math.signum or java.math.BigDecimal , especially for currency & tax computing
Watch out for auto-unboxing:
Double someAmount = null;
if ( someAmount <= 0){
Boom, NullPointerException.
Yes you should be careful.
Suggestion : One of the good way would be using BigDecimal for checking equality/non-equality to 0:
BigDecimal balance = pojo.getBalance();//get your BigDecimal obj
0 != balance.compareTo(BigDecimal.ZERO)
Explanation :
The compareTo() function compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for performing these comparisons is: (x.compareTo(y) <op> 0), where is one of the six comparison operators.
(Thanks to SonarQube documentation)
Floating point math is imprecise because of the challenges of storing such values in a binary representation. Even worse, floating point math is not associative; push a float or a double through a series of simple mathematical operations and the answer will be different based on the order of those operation because of the rounding that takes place at each step.
Even simple floating point assignments are not simple:
float f = 0.1; // 0.100000001490116119384765625
double d = 0.1; // 0.1000000000000000055511151231257827021181583404541015625
(Results will vary based on compiler and compiler settings);
Therefore, the use of the equality (==) and inequality (!=) operators on float or double values is almost always an error. Instead the best course is to avoid floating point comparisons altogether. When that is not possible, you should consider using one of Java's float-handling Numbers such as BigDecimal which can properly handle floating point comparisons. A third option is to look not for equality but for whether the value is close enough. I.e. compare the absolute value of the difference between the stored value and the expected value against a margin of acceptable error. Note that this does not cover all cases (NaN and Infinity for instance).
If you don't care about the edge cases, then just test for someAmount <= 0. It makes the intent of the code clear. If you do care, well... it depends on how you calculate someAmount and why you're testing for the inequality.
Check a double or float value is 0, an error threshold is used to detect if the value is near 0, but not quite 0. I think this method is the best what I met.
How to test if a double is zero?
Answered by #William Morrison
public boolean isZero(double value, double threshold){
return value >= -threshold && value <= threshold;
}
For example, set threshold as 0. like this,
System.out.println(isZero(0.00, 0));
System.out.println(isZero(0, 0));
System.out.println(isZero(0.00001, 0));
The results as true, true and false from above example codes.
Have Fun #.#