I work on a product called Oracle RPAS as a consultant and the application is developed using C++. In Oracle RPAS , JNI calls can be made to custom developed Java programs to process the data.
The data stored in Oracle RPAS for Real is always Double(8 bytes) and same is available in Java. Unfortunately Oracle RPAS is using a hard coded value of 0.0000000001 (1e-09) as epsilon for comparing doubles and other calculations even though data is stored in database as Double.
In Java I am not able to find out a way to align the code with this hard coded value. I need to compare the dataset in similar way . These are the mathematical operations, I need to perform mostly
min(double x,double Y) , max(double x,double Y) round(double x*double Y)/ double Y) , ceil ,floor etc.
I need help in understanding how epsilon works in Java ?
Java version used for development is 1.6
I am not an expert in Java and have some coding experience in it and any starting point will be helpful to tackle this problem.
The whole idea of epsilon should be base on your application logic. If you are going to deal with data which you expect to have value till the 3rd decimal place, then use an epsilon like 0.0001. Or similarly, if you know your application is going to deal with number up to a billion (1,000,000,000), then you know double can be at most accurate til the 5-6th decimal places (15 significant figures minus 10 digits before decimal). Hence choosing 0.000001 as epsilon will be reasonable.
As far as I know, Java does not do any internal epsilon handling during double comparison. It needs to be done explicitly, just like when you are writing C/C++.
Of course you may also consider BigDecimal as an alternative. However you still need to define the precision you want to keep when you are doing BigDecimal arithmetic, with somewhat similar reasoning like epsilon for double.
In Java you use BigDecimal instead of Double and then you don't need to use any epsilon at all.
Related
I know float type is A IEEE floating point, and it's not accuracy in calculation, for example, if I'd like to sum two floats 8.4 and 2.4, what I get is 10.7999999 rather than 10.8. I also know BigDecimal can solve this problem, but BigDecimal is much slower than float type.
In most real productions we'd like an accuracy value like above 10.8 not a 10.7999.. so my question is shall I prevent to use float as much as I can in programming? if not is there any use cases? I mean in a real production.
If you're handling monetary amounts, then numbers like 8.4 and 2.4 are exact values, and you'll want to use BigDecimal for those. However, if you're doing a physics calculation where you're dealing with measurements, the values 8.4 and 2.4 aren't going to be exact anyway, since measurements aren't exact. That's a use case where using double is better. Also, a scientific calculation could involve things like square roots, trigonometric functions, logarithms, etc., and those can be done only using IEEE floats. Calculations involving money don't normally involve those kinds of functions.
By the way, there's very little reason to ever use the float type; stick with double.
You use float when the percision is enough. It is generally faster to do calculations with float and requires less memory. Sometimes you just need the performance.
What you describe is caused by the fact that binary floating point numbers cannot exactly represent many numbers that can be exactly represented by decimal floating point numbers, like 8.4 or 2.4.
This affects not only the float type in Java but also double.
In many cases you can do calculations with integers and then rescale to get the deciamls correctly. But if you require numbers with equal relative accurracies, no matter how large they are, floating point is far superior.
So yes, if you can, you should prefer integers over floats, but there are many applications where floating point is required. This includes many scientific and mathematical algorithms.
You should also consider that 10.7999999 instead of 10.8 looks weird when displayed but actually the difference is really small. So it's not so much an accurracy issue but more related to number formatting. In most cases this problem is resolved by rounding the number appropriately when converting it to a string for output, for example:
String price = String.format("%.2f", floatPrice);
BigDecimals are very precise (you can determine their precision -- it is mainly limited by memory) but pretty slow and memory intensive. You use them when you need exact results, i.e. in financial applications, or when you otherwise need very precise results and when speed is not too critical.
Floating point types (double and float) are not nearly as precise, but much faster and they only take up limited memory. Typically, a float takes up 4 bytes and a double takes up 8 bytes. You use them with measurements that can't be very exact anyway, but also if you need the speed or the memory. I use them for (real time) graphics and real time music. Or when otherwise precision of the result is not so important, e.g. when measuring time or percentages when downloading or some such.
I have a Java project that deals with a lot money values and the project mainly involves:
reading the data from database,
calculations (process data)
showing to users (no inserts or updates in database are required).
I need precision for only some of the money values and not for all. So here I can do:
using doubles when precision not required or
using BigDecimals for ALL.
I want to know if there will be any performance issues if I use BigDecimal for all the variables? Can I save execution time if I opt for choice 1?
Which way is best? (I am using java 6)
Don't use double for money Why not use Double or Float to represent currency?
Using Big Decimal is 100x slower than the built in primitives and you can't use + and -, / and * with BigDecimal but must use the equivalent BigDecimal method calls.
An alternative is to use int instead of double where you are counting cents or whatever fractional currency equivalent and then when formatting the output to the user, do the appropriate conversions back to show the values the way the user expects.
If you have really large values, you can use long instead of int
It's a trade-off.
With BigDecimal you are working with immutable objects. This means that each operation will cause the creation of new objects and this, for sure, will have some impact on the memory. How much - it depends on a lot of things - execution environment, number and complexity of the calculations, etc. But you are getting precision, which is the most important thing when working with money.
With double you can use primitive values, but the precision is poor and they are not suitable for money calculation at all.
If I had to suggest a way - I would say for sure use BigDecimal when dealing with money.
Have you considered moving some of the calculation logic to the DB layer? This can save you a lot in terms of memory and performance, and you will still keep the precision requirement in tact.
BigDecimal and double are very different types, with very different purposes. Java benefits from having both, and Java programmers should be using both of them appropriately.
The floating point primitives are based on binary to be both space and time efficient. They can be, and typically are, implemented in very fast hardware. double should be used in contexts in which there is nothing special about terminating decimal fractions, and all that is needed is an extremely close approximation to a value that may be fractional, irrational, very big, or very small. There are good implementations of many trig and similar functions for double. See java.lang.Math for some examples.
BigDecimal can represent any terminating decimal fraction exactly, given enough memory. That is very, very good in situations in which terminating decimal fractions have special status, such as many money calculations.
In addition to exact representation of terminating decimal fractions, it could also be used to get a closer approximation to e.g. one third than is possible with double. However, situations in which you need an approximation that is closer than double supplies are very rare. The closest double to one third is 0.333333333333333314829616256247390992939472198486328125, which is close enough for most practical purposes. Try measuring the difference between one third of an inch and 0.3333333333333333 inches.
BigDecimal is a only supported in software, does not have the support for mathematical functions that double has, and is much less space and time efficient.
If you have a job for which either would work functionally, use double. If you need exact representation of terminating decimal fractions, use BigDecimal.
I am trying to establish some concise overview of what options for precise caluclations we have in JAVA+SQL. So far I have found following options:
use doubles accepting their drawbacks, no go.
use BigDecimals
using them in complicated formulas is problematic for me
use String.format/Decimal.format to round doubles
do i need to round each variable in formula or just result to get BigDecimal precision?
how can this be tweaked?
use computed fields option in SQL.
drawback is that I'd need dynamic SQL to pull data from different tables + calculate fields on other calculated fields and that would get messy
any other options?
Problem statement:
I need precise financial calculations that would involve using very big (billions) and very small numbers (0.0000004321), and also dividing values that are very similar to each other, so for sure I need precision of BigDecimal.
On the other side, I want to retain ease of use that doubles have in functions (i work on arrays from decimal SQL data), so calculations like: (a[i] - b[i])/b[i] etc. etc. that are further used in other calculations. and I'd like to have users to be able to desing their own formulas as they need them (using common math statements)
i am keen to use "formatting" solution for String.format, but this makes code not very readable ( using String.format() for each variable...).
Many thanks for suggestion of how to deal with the stuff.
There is nothing you can do to avoid floating point erros in float and double.
No free cheese here - use BigDecimal.
From Effective Java (2nd ED):
Item 48: Avoid float and double if exact answers are required
Float and double do not provide exact results and should not be used where exact results are required.
The float and double types are particularly ill-suited for monetary claculations because is impossible to represent 0.1 (or any other negative power of ten) as a float or double exactly.
The right way to solve this problem is to ouse BigDecimal, int, or long for monetary calculations.
...
An alternative is to use int or long and to keep track of the decimal point yourself.
There is no way to get BigDecimal precision on a double. doubles have double precision.
If you want to guarantee precise results use BigDecimal.
You could create your own variant using a long to store the integer part and an int to store the fractional part - but why reinvent the wheel.
Any time use doubles you stand to stuffer from double precision issues. If you use them in a single place you might as well use them everywhere.
Even if you only use them to represent data from the database then will round the data to double precision and you will lose information.
If I understand your question, you want to use Data Types with more precision than the native Java ones without loosing the simple mathematical syntax (e.g. / + * - and so on). As you cannot overload operators in Java, I think this is not possible.
According to IEEE the following doubles exist:
Mantissa Exponent
double 64bit: 52 bit 11 bit
double 80bit: 64 bit 15 bit
In Java only the 64bit double can be directly
stored in an instance variable. I would like for
whatever reason work with 80bit floats as defined
above in Java. I am interested in the full set
of arithmetic functions, I/O and trigonometric
functions. How could I do that?
One could of course do something along the
following lines:
public class DoubleExt {
private long mantissa;
private short exponent;
}
And then make a package that interfaces with
some of the known C libs for 80bit floats.
But would this be considered the best practice?
What about supporting a couple of plattforms
and architectures?
Bye
I'm pretty sure primitives won't get you there, but the BigDecimal class is as good as it gets (for everything except trigonometry).
For trigonometric functions, however, you will have to resort to an external library, like APFloat (see this previous question).
Perhaps BigDecimal is an adequate way for you. But I believe it doesn't provide the full set of mathematic functions.
http://download.oracle.com/javase/1,5.0/docs/api/java/math/BigDecimal.html
The question is already 5 years old. Time to look around
whether there are some new candidates, maybe draw inspiraction
from other languages.
In Racket we find a BigFloat data type:
https://docs.racket-lang.org/math/bigfloat.html
The underlying library is GNU MPFR, a Java interface was started:
https://github.com/kframework/mpfr-java
Is this the only interface so far?
Why the inconsistency?
There is no inconsistency: the methods are simply designed to follow different specifications.
long round(double a)
Returns the closest long to the argument.
double floor(double a)
Returns the largest (closest to positive infinity) double value that is less than or equal to the argument and is equal to a mathematical integer.
Compare with double ceil(double a)
double rint(double a)
Returns the double value that is closest in value to the argument and is equal to a mathematical integer
So by design round rounds to a long and rint rounds to a double. This has always been the case since JDK 1.0.
Other methods were added in JDK 1.2 (e.g. toRadians, toDegrees); others were added in 1.5 (e.g. log10, ulp, signum, etc), and yet some more were added in 1.6 (e.g. copySign, getExponent, nextUp, etc) (look for the Since: metadata in the documentation); but round and rint have always had each other the way they are now since the beginning.
Arguably, perhaps instead of long round and double rint, it'd be more "consistent" to name them double round and long rlong, but this is argumentative. That said, if you insist on categorically calling this an "inconsistency", then the reason may be as unsatisfying as "because it's inevitable".
Here's a quote from Effective Java 2nd Edition, Item 40: Design method signatures carefully:
When in doubt, look to the Java library APIs for guidance. While there are plenty of inconsistencies -- inevitable, given the size and scope of these libraries -- there are also fair amount of consensus.
Distantly related questions
Why does int num = Integer.getInteger("123") throw NullPointerException?
Most awkward/misleading method in Java Base API ?
Most Astonishing Violation of the Principle of Least Astonishment
floor would have been chosen to match the standard c routine in math.h (rint, mentioned in another answer, is also present in that library, and returns a double, as in java).
but round was not a standard function in c at that time (it's not mentioned in C89 - c identifiers and standards; c99 does define round and it returns a double, as you would expect). it's normal for language designers to "borrow" ideas, so maybe it comes from some other language? fortran 77 doesn't have a function of that name and i am not sure what else would have been used back then as a reference. perhaps vb - that does have Round but, unfortunately for this theory, it returns a double (php too). interestingly, perl deliberately avoids defining round.
[update: hmmm. looks like smalltalk returns integers. i don't know enough about smalltalk to know if that is correct and/or general, and the method is called rounded, but it might be the source. smalltalk did influence java in some ways (although more conceptually than in details).]
if it's not smalltalk, then we're left with the hypothesis that someone simply chose poorly (given the implicit conversions possible in java it seems to me that returning a double would have been more useful, since then it can be used both while converting types and when doing floating point calculations).
in other words: functions common to java and c tend to be consistent with the c library standard at the time; the rest seem to be arbitrary, but this particular wrinkle may have come from smalltalk.
I agree, that it is odd that Math.round(double) returns long. If large double values are cast to long (which is what Math.round implicitly does), Long.MAX_VALUE is returned. An alternative is using Math.rint() in order to avoid that. However, Math.rint() has a somewhat strange rounding behavior: ties are settled by rounding to the even integer, i.e. 4.5 is rounded down to 4.0 but 5.5 is rounded up to 6.0). Another alternative is to use Math.floor(x+0.5). But be aware that 1.5 is rounded to 2 while -1.5 is rounded to -1, not -2. Yet another alternative is to use Math.round, but only if the number is in the range between Long.MIN_VALUE and Long.MAX_VALUE. Double precision floating point values outside this range are integers anyhow.
Unfortunately, why Math.round() returns long is unknown. Somebody made that decision, and he probably never gave an interview to tell us why. My guess is, that Math.round was designed to provide a better way (i.e., with rounding) for converting doubles to longs.
Like everyone else here I also don't know the answer, but thought someone might find this useful. I noticed that if you want to round a double to an int without casting, you can use the two round implementations long round(double) and int round(float) together:
double d = something;
int i = Math.round(Math.round(d));