I'm writing a method of a Network Calculator that calculates how many bits are needed giving a number of hosts. This is the piece of code that is giving me some problems:
int hostBits = (int) Math.ceil(Math.log(hosts) / Math.log(2));
It works fine with small numbers, but the problem comes up when I enter big ones, like 2^31 - 2, because the result of Math.log(hosts) / Math.log(2) (changing the base of the logarithm), that should be 31.0, actually is 31.000000000000004.
Then, Math.ceil(...) brings 31.000000000000004 to 32 and not to 31 as I want.
Does anyone have an idea how to solve this?
Not the problem.
The problem is only that when a number is divided , for example two different integers (int's) the result particularly with "Math" and log methods is "precision" that it expects may well be required to be some custom level or default level of a primitive type such as double - hence the extra decimal places after the decimal point.
Two points, first, when a number is divided that technically would simply be an integer e.g. 12 / 3 = 6 with math and as a primitive type double it will always have decimal point followed by around six zero's or so and a number other than 0 at the end. Second, it could appear worse from the Math library you could get logarithmic notations from a division not decimal places.
A final point, the Math library does not know what the answer will be until it does it so using double type is an automatic conversion no matter how you write it for safety of precision and data type.
Automatic swapping of data types is known as promotion (raising precision int to a float) or demotion (lowering precision double to a float)
And to convert it to an integer it will round up or down by rules of the first following decimal place from the point, so you basically only need to put the answer into a "new Double(primativedoubletype)" object and use its "intValue" method.
NB putting an (int) cast in front of it only ensures that it is an int when assigned (generally from an expression or method) to an int variable, however it is not a way of extracting the value of another type to an int, the primitive type must be converted through its standard java type class object with its primatves converter method.
int hostBits2 = new Double((double)Math.ceil(Math.log(hosts) / Math.log(2)+1e-10)).intValue();
Try using epsilon while rounding
int hostBits2 = (int) Math.ceil(Math.log(hosts) / Math.log(2)+1e-10);
Related
We are solving a numeric precision related bug. Our system collects some numbers and spits their sum.
The issue is that the system does not retain the numeric precision, e.g. 300.7 + 400.9 = 701.599..., while expected result would be 701.6. The precision is supposed to adapt to the input values so we cannot just round results to fixed precision.
The problem is obvious, we use double for the values and addition accumulates the error from the binary representation of the decimal value.
The path of the data is following:
XML file, type xsd:decimal
Parse into a java primitive double. Its 15 decimal places should be enough, we expect values no longer than 10 digits total, 5 fraction digits.
Store into DB MySql 5.5, type double
Load via Hibernate into a JPA entity, i.e. still primitive double
Sum bunch of these values
Print the sum into another XML file
Now, I assume the optimal solution would be converting everything to a decimal format. Unsurprisingly, there is a pressure to go with the cheapest solution. It turns out that converting doubles to BigDecimal just before adding a couple of numbers works in case B in following example:
import java.math.BigDecimal;
public class Arithmetic {
public static void main(String[] args) {
double a = 0.3;
double b = -0.2;
// A
System.out.println(a + b);//0.09999999999999998
// B
System.out.println(BigDecimal.valueOf(a).add(BigDecimal.valueOf(b)));//0.1
// C
System.out.println(new BigDecimal(a).add(new BigDecimal(b)));//0.099999999999999977795539507496869191527366638183593750
}
}
More about this:
Why do we need to convert the double into a string, before we can convert it into a BigDecimal?
Unpredictability of the BigDecimal(double) constructor
I am worried that such a workaround would be a ticking bomb.
First, I am not so sure that this arithmetic is bullet proof for all cases.
Second, there is still some risk that someone in the future might implement some changes and change B to C, because this pitfall is far from obvious and even a unit test may fail to reveal the bug.
I would be willing to live with the second point but the question is: Would this workaround provide correct results? Could there be a case where somehow
Double.valueOf("12345.12345").toString().equals("12345.12345")
is false? Given that Double.toString, according to javadoc, prints just the digits needed to uniquely represent underlying double value, so when parsed again, it gives the same double value? Isn't that sufficient for this use case where I only need to add the numbers and print the sum with this magical Double.toString(Double d) method? To be clear, I do prefer what I consider the clean solution, using BigDecimal everywhere, but I am kind of short of arguments to sell it, by which I mean ideally an example where conversion to BigDecimal before addition fails to do the job described above.
If you can't avoid parsing into primitive double or store as double, you should convert to BigDecimal as early as possible.
double can't exactly represent decimal fractions. The value in double x = 7.3; will never be exactly 7.3, but something very very close to it, with a difference visible from the 16th digit or so on to the right (giving 50 decimal places or so). Don't be mislead by the fact that printing might give exactly "7.3", as printing already does some kind of rounding and doesn't show the number exactly.
If you do lots of computations with double numbers, the tiny differences will eventually sum up until they exceed your tolerance. So using doubles in computations where decimal fractions are needed, is indeed a ticking bomb.
[...] we expect values no longer than 10 digits total, 5 fraction digits.
I read that assertion to mean that all numbers you deal with, are to be exact multiples of 0.00001, without any further digits. You can convert doubles to such BigDecimals with
new BigDecimal.valueOf(Math.round(doubleVal * 100000), 5)
This will give you an exact representation of a number with 5 decimal fraction digits, the 5-fraction-digits one that's closest to the input doubleVal. This way you correct for the tiny differences between the doubleVal and the decimal number that you originally meant.
If you'd simply use BigDecimal.valueOf(double val), you'd go through the string representation of the double you're using, which can't guarantee that it's what you want. It depends on a rounding process inside the Double class which tries to represent the double-approximation of 7.3 (being maybe 7.30000000000000123456789123456789125) with the most plausible number of decimal digits. It happens to result in "7.3" (and, kudos to the developers, quite often matches the "expected" string) and not "7.300000000000001" or "7.3000000000000012" which both seem equally plausible to me.
That's why I recommend not to rely on that rounding, but to do the rounding yourself by decimal shifting 5 places, then rounding to the nearest long, and constructing a BigDecimal scaled back by 5 decimal places. This guarantees that you get an exact value with (at most) 5 fractional decimal places.
Then do your computations with the BigDecimals (using the appropriate MathContext for rounding, if necessary).
When you finally have to store the number as a double, use BigDecimal.doubleValue(). The resulting double will be close enough to the decimal that the above-mentioned conversion will surely give you the same BigDecimal that you had before (unless you have really huge numbers like 10 digits before the decimal point - the you're lost with double anyway).
P.S. Be sure to use BigDecimal only if decimal fractions are relevant to you - there were times when the British Shilling currency consisted of twelve Pence. Representing fractional Pounds as BigDecimal would give a disaster much worse than using doubles.
It depends on the Database you are using. If you are using SQL Server you can use data type as numeric(12, 8) where 12 represent numeric value and 8 represents precision. similarly, for my SQL DECIMAL(5,2) you can use.
You won't lose any precision value if you use the above-mentioned datatype.
Java Hibernate Class :
You can define
private double latitude;
Database:
I was just messing around with this method to see what it does. I created a variable with value 3.14 just because it came to my mind at that instance.
double n = 3.14;
System.out.println(Math.nextUp(n));
The preceding displayed 3.1400000000000006.
Tried with 3.1400000000000001, displayed the same.
Tried with 333.33, displayed 333.33000000000004.
With many other values, it displays the appropriate value for example 73.6 results with 73.60000000000001.
What happens to the values in between 3.1400000000000000 and 3.1400000000000006? Why does it skips some values? I know about the hardware related problems but sometimes it works right. Also even though it is known that precise operations cannot be done, why is such method included in the library? It looks pretty useless due to the fact that it doesn't work always right.
One useful trick in Java is to use the exactness of new BigDecimal(double) and of BigDecimal's toString to show the exact value of a double:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
System.out.println(new BigDecimal(3.14));
System.out.println(new BigDecimal(3.1400000000000001));
System.out.println(new BigDecimal(3.1400000000000006));
}
}
Output:
3.140000000000000124344978758017532527446746826171875
3.140000000000000124344978758017532527446746826171875
3.1400000000000005684341886080801486968994140625
There are a finite number of doubles, so only a specific subset of the real numbers are the exact value of a double. When you create a double literal, the decimal number you type is represented by the nearest of those values. When you output a double, by default, it is shown as the shortest decimal fraction that would round to it on input. You need to do something like the BigDecimal technique I used in the program to see the exact value.
In this case, both 3.14 and 3.1400000000000001 are closer to 3.140000000000000124344978758017532527446746826171875 than to any other double. The next exactly representable number above that is 3.1400000000000005684341886080801486968994140625
Floating point numbers are stored in binary: the decimal representation is just for human consumption.
Using Rick Regan's decimal to floating point converter 3.14 converts to:
11.001000111101011100001010001111010111000010100011111
and 3.1400000000000006 converts to
11.0010001111010111000010100011110101110000101001
which is indeed the next binary number to 53 significant bits.
Like #jgreve mentions this has to do due to the use of float & double primitives types in java, which leads to the so called rounding error. The primitive type int on the other hand is a fixed-point number meaning that it is able to "fit" within 32-bits. Doubles are not fixed-point, meaning that the result of double calculations must often be rounded in order to fit back into its finite representation, which leads sometimes (as presented in your case) to inconsistent values.
See the following two links for more info.
https://stackoverflow.com/a/322875/6012392
https://en.wikipedia.org/wiki/Double-precision_floating-point_format
A work around could be the following two, which gives a "direction" to the first double.
double n = 1.4;
double x = 1.5;
System.out.println(Math.nextAfter(n, x));
or
double n = 1.4;
double next = n + Math.ulp(n);
System.out.println(next);
But to handle floating point values it is recommended to use the BigDecimal class
I would like to be able to convert a large Double to an Integer, but it seems that the Frege Haskell implementation of floor does not yield an Integral type. Instead, it seems to be implemented to interface with way Java does it, and takes a Floating type to a Double, Floating r => r -> Double. I could use round, but that rounds rather than truncate (though I might be able to subtract 0.5 and then round). I'd rather work without needing to resort to using Int or Long, which, as wide as the latter is, is still limited in precision.
Any way to go about flooring a floating point type to an arbitrary precision integer type?
This functionality is indeed not available. The reason is that Java apparently doesn't offer methods that support it.
What you can do is to convert the (floored) double to a String and converting that to an Integer.
Here is an example:
frege> import Prelude.Math(floor)
frege> integerFromDouble d = String.aton ("%.0f".format (floor d))
function integerFromDouble :: Math.Floating a => a -> Integer
frege> integerFromDouble 987654321e20
98765432100000000000000000000
I wonder if there is a more effective method that somehow extracts the mantissa and exponent from a Double and computes the Integer.
Note that above function is unsafe because NaN, +Infinity and -Infinity exist:
frege> integerFromDouble (5/0)
java.lang.NumberFormatException: For input string: "Infinity"
You could either check that separately or replace String.aton with String.integer , which returns
Either NumberFormatException Integer
If you can make sure your computations don't exceed the Long capacity, what you want can be done with:
round . floor
You could also just call intValue on the Double result after calling floor.
http://docs.oracle.com/javase/6/docs/api/java/lang/Number.html#intValue%28%29
I'm developing a chemistry app, and I need to include the Avogadro's number:
(602200000000000000000000)
I don't really know if I can use scientific notation to represent it as 6.022 x 10x23 (can't put the exponent).
I first used double, then long and now, I used java.math.BigInteger.
But it still says it's too big, what can I do or should this is just to much for a system?
Pass it to the BigInteger constructor as a String, and it works just fine.
BigInteger a = new BigInteger("602200000000000000000000");
a = a.multiply(new BigInteger("2"));
System.out.println(a);
Output: 1204400000000000000000000
First of all, you need to check your physics / chemistry text book.
Avogadro's number is not 602,200,000,000,000,000,000,000. It is approximately 6.022 x 1023. The key word is "approximately". As of 2019, the precise value is 6.02214076×1023 mol−1
(In 2015 when I originally wrote this reply, the current best approximation for Avogadro's number was 6.022140857(74)×1023 mol−1, and the relative error was +/- 1.2×10–8. In 2019, the SI redefined the mole / Avogadro's number to be the precise value above. Source: Wikipedia)
My original (2015) answer was that since the number only needed 8 decimal digits precision, the Java double type was an appropriate type to represent it. Hence, I recommended:
final double AVOGADROS_CONSTANT = 6.02214076E23;
Clearly, neither int or long can represent this number. A float could, but not with enough precision (assuming we use the best available measured value).
Now (post 2019) the BigInteger is the simplest correct representation.
Now to your apparent problems with declaring the constant as (variously) an double, a long and a BigInteger.
I expect you did something like this:
double a = 602200000000000000000000;
and so on. That isn't going to work, but the reason it won't work needs to be explained. The problem is that the number is being supplied as an int literal. An int cannot be that big. The largest possible int value is 231 - 1 ... which is a little bit bigger than 2 x 109.
That is what the Java compiler was complaining about. The literal is too big to be an int.
It is too big for long literal as well. (Do the math.)
But it is not too big for a double literal ... provided that you write it correctly.
The solution using BigInteger(String) works because it side-steps the problem of representing the number as a numeric literal by using a string instead, and parsing it at runtime. That's OK from the perspective of the language, but (IMO) wrong because the extra precision is an illusion.
You can use E notation to write the scientific notation:
double a = 6.022e23;
The problem is with how you're trying to create it (most likely), not because it can't fit.
If you have just a number literal in your code (even if you try to assign it to a double or long), this is first treated as an integer (before being converted to the type it needs to be), and the number you have can't fit into an integer.
// Even though this number can fit into a long, it won't compile, because it's first treated
// as an integer.
long l = 123456788901234;
To create a long, you can add L to your number, so 602200000000000000000000L, although it won't fit into a long either - the max value is 263-1.
To create a double, you can add .0 to your number, so 602200000000000000000000.0 (or 6.022e23 as Guffa suggested), although you should not use this if you want precise values, as you may lose some accuracy because of the way it stores the value.
To create a BigInteger, you can use the constructor taking a string parameter:
new BigInteger("602200000000000000000000");
Most probably you are using long to initialize BigInteger. Since long can represent 64-bit numbers, your number would be too big to fit in to long. Using String would help.
I'm extremely new to Java and just wanted to confirm what Double is? Is it similar to Float or Int? Any help would be appreciated. I also sometimes see the uppercase Double and other times the lower case double. If someone could clarify what this means that'd be great!
Double is a wrapper class,
The Double class wraps a value of the
primitive type double in an object. An
object of type Double contains a
single field whose type is double.
In addition, this class provides
several methods for converting a
double to a String and a String to a
double, as well as other constants and
methods useful when dealing with a
double.
The double data type,
The double data type is a
double-precision 64-bit IEEE 754
floating point. Its range of values is
4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative).
For decimal values, this data type is
generally the default choice. As
mentioned above, this data type should
never be used for precise values, such
as currency.
Check each datatype with their ranges : Java's Primitive Data Types.
Important Note : If you'r thinking to use double for precise values, you need to re-think before using it. Java Traps: double
In a comment on #paxdiablo's answer, you asked:
"So basically, is it better to use Double than Float?"
That is a complicated question. I will deal with it in two parts
Deciding between double versus float
On the one hand, a double occupies 8 bytes versus 4 bytes for a float. If you have many of them, this may be significant, though it may also have no impact. (Consider the case where the values are in fields or local variables on a 64bit machine, and the JVM aligns them on 64 bit boundaries.) Additionally, floating point arithmetic with double values is typically slower than with float values ... though once again this is hardware dependent.
On the other hand, a double can represent larger (and smaller) numbers than a float and can represent them with more than twice the precision. For the details, refer to Wikipedia.
The tricky question is knowing whether you actually need the extra range and precision of a double. In some cases it is obvious that you need it. In others it is not so obvious. For instance if you are doing calculations such as inverting a matrix or calculating a standard deviation, the extra precision may be critical. On the other hand, in some cases not even double is going to give you enough precision. (And beware of the trap of expecting float and double to give you an exact representation. They won't and they can't!)
There is a branch of mathematics called Numerical Analysis that deals with the effects of rounding error, etc in practical numerical calculations. It used to be a standard part of computer science courses ... back in the 1970's.
Deciding between Double versus Float
For the Double versus Float case, the issues of precision and range are the same as for double versus float, but the relative performance measures will be slightly different.
A Double (on a 32 bit machine) typically takes 16 bytes + 4 bytes for the reference, compared with 12 + 4 bytes for a Float. Compare this to 8 bytes versus 4 bytes for the double versus float case. So the ratio is 5 to 4 versus 2 to 1.
Arithmetic involving Double and Float typically involves dereferencing the pointer and creating a new object to hold the result (depending on the circumstances). These extra overheads also affect the ratios in favor of the Double case.
Correctness
Having said all that, the most important thing is correctness, and this typically means getting the most accurate answer. And even if accuracy is not critical, it is usually not wrong to be "too accurate". So, the simple "rule of thumb" is to use double in preference to float, UNLESS there is an overriding performance requirement, AND you have solid evidence that using float will make a difference with respect to that requirement.
A double is an IEEE754 double-precision floating point number, similar to a float but with a larger range and precision.
IEEE754 single precision numbers have 32 bits (1 sign, 8 exponent and 23 mantissa bits) while double precision numbers have 64 bits (1 sign, 11 exponent and 52 mantissa bits).
A Double in Java is the class version of the double basic type - you can use doubles but, if you want to do something with them that requires them to be an object (such as put them in a collection), you'll need to box them up in a Double object.