I am studying for java certification. And i'm curious about the java literals.
I know it is possible to do something like this:
int i = 0xAA;
long l = 0xAAL;
Also this is possible for floating-point variables:
double d = 123d;
float f = 123f;
So I logically thought with these examples that the same would apply for hexadecimal. Just like i can add L for long literals, I could add 'd' or 'f' but the logic is flawed since 'F' and 'D' are valid hexadecimal values.
It is not possible to do something like this:
double d = 0xAAAAAAAAAAAAAAAAAAd;
Is this just not allowed by Java or there is a simple way to do it that I don't know?
It turns out it is possible, although that surprised me. Section 3.10.2 of the JLS gives the structure of floating point literals, including HexadecimalFloatingPointLiteral.
public class Test {
public static void main(String[] args) {
double d1 = 0xAAAAAAAAAAAAAAAAAAp0d;
double d2 = 0x1.8p1d;
System.out.println(d1); // A very big number
System.out.println(d2); // 24 = 1.5 * 2^1
}
}
The p is required as part of the binary exponent - the value after the p is the number of bits to shift the value left. Other examples:
0x1.4p0d => 1.25 (binary 0.01 shifted 0 bits)
0x8p-4d => 0.5 (binary 1000 shifted *right* 4 bits)
Related
I have been trying the following code in Java :
import java.math.*;
public class trial {
public static void main(String[] args) {
// create a BigDecimal object
BigDecimal bg;
// create a Float object
Float f;
float f2 = 35912062;
bg = new BigDecimal(35912062);
// assign the converted value of bg to f
f = bg.floatValue();
String str = "Float value of " + bg + " is " + f;
bg = new BigDecimal(f);
String str2 = "BigDecimal value of " + bg;
// print f value
System.out.println( str );
System.out.println( str2 );
System.out.println( 35912062f );
System.out.println(f2);
}
}
So, the following is the output I am getting :
Float value of 35912062 is 3.5912064E7
BigDecimal value of 35912064
3.5912064E7
3.5912064E7
Now, I believe that it is because this is extending the range of float but when I read this :
What is the inclusive range of float and double in Java?
it shows the inclusive range of float to be : 3.40282346638528860e+38
This has made me really confused.
Any links giving explanations will help.
EDIT:
Say I take 25912062 inplace of 35912062, The output for 25912062 is 25912062, but for, 35912062 the output is 35912064 why is this so ?
Basically, floating point values are stored as a pair of mantissa and exponent. The mantissa describes the significant digits of the number (think of it as a number between 0 and 9.99). The exponent is the scale. Your number is presented as mantissa * 2^x.
We are talking about a representation in the binary system, which makes even straight numbers (in the decimal system) like 35912062 to something which may not exactly fit within the precision of the mantissa. In these cases, you get some rounding issues, especially as float has a rather limited range for the mantissa.
Executing your code with double (instead of float) gives you 3.5912062E7 as result.
If your really wanna know what java (or the floating point arithmetic) makes of your number, you should do System.out.println(new Bigdecimal(123.456)) and be surprised.
The message here is, if you really need precise arithmetics always take BigDecimal. Because there are further caveats. For example, adding a large double and a small double may result in the small double to be rounded away completely. That takes us to a funny thing:
for (float f = 35912062f; f < 55912062f; f++) {
System.out.println(f);
}
will never terminate. Just try it.
This question already has answers here:
fixed point arithmetics in java with fast performance
(4 answers)
Closed 7 years ago.
I have two double variables:
double a = 1.109
double b = 5.0E-5;
But b is changable and I want to achieve fixed numbers of decimal places depending of b number, for example above I want achieve this result:
Result = 1.10900
But not only print, I need to send it to other method and my double must have fixed numbers of decimal places like in example.
It sounds like you want arbitrary precision on the actual value (as opposed to just output). double doesn't give you that. BigDecimal does though. Its BigDecimal(String) constructor sets the value and the scale (number of places to the right of the decimal) from a string, so:
BigDecimal d = new BigDecimal("1.10900");
BigDecimal then gives you various math operations to stay within that scale, with various rounding options.
If at some point you need to get the double value of the BigDecimal, you can use its doubleValue method. But note that at that point, again, you don't have a fixed number of places to the right of the decimal anymore.
Here's an example contrasting BigDecimal and double (Live Copy):
import java.math.*;
class Example
{
public static void main (String[] args) throws java.lang.Exception
{
BigDecimal bd = new BigDecimal("1.10900");
bd = bd.divide(new BigDecimal("27"), BigDecimal.ROUND_HALF_DOWN);
System.out.println("1.109 / 27 using BigDecimal to five places: " + bd);
double d = 1.109;
d = d / 27.0;
System.out.println("1.109 / 27 using double: " + d);
}
}
Output:
1.109 / 27 using BigDecimal to five places: 0.04107
1.109 / 27 using double: 0.041074074074074075
Try using a number formatter:
NumberFormat formatter = new DecimalFormat("#0.00000");
double a = 1.109;
double b = 5.0E-5;
System.out.println(a);
System.out.println(b);
Output:
1.10900
0.00005
A simple solution is to round the result as needed. This is not only faster than using BigDecimal it can be less error prone as Java doesn't have language support for BigDecimal making it harder to write/read and validate. A simple method for rounding half up for 5 decimal spaces is
public static double round5(double d) {
final double factor = 1e5;
return d > Long.MAX_VALUE / factor || d < -Long.MAX_VALUE / factor ? d :
(long) (d < 0 ? d * factor - 0.5 : d * factor + 0.5) / factor;
}
Note: when you print the double you will still need to specify the number of decimal places you need e.g.
System.out.printf("%.5f", value);
Use java printf-like routine (note it produces platform dependent decimal separators):
String.format("%.5f", a)
I think that question is pretty straight. but here is an examples.
Example below is OK. I can take rounding and no truncating was done here.
public static void main(String[] args) {
double d = 9.9;
long l = (long)d;
System.out.println(l);
}
Output:
9
And now number out of range of long:
public static void main(String[] args) {
double d = 99999999999999999999999999999999.9;
long l = (long)d;
System.out.println(l);
}
Output:
9223372036854775807
This one troubles me. I cannot continue work with completely different number. I would rather get an error or an exception.
Is there any way to detect this in Java?
You can compare it with Long.MIN_VALUE and Long.MAX_VALUE:
public static boolean fitsLong(double d) {
return d >= Long.MIN_VALUE && d < Long.MAX_VALUE;
}
Somewhat more sofisticated approach is to use BigDecimal:
double value = 1234567.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // 1234568
double value = 99999999999999999999999999999999.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
This way you can control how the rounding is performed.
You may ask, why there's strict inequality in fitsLong: d < Long.MAX_VALUE. Actually that's because the Long.MAX_VALUE itself cannot be represented as double number. When you cast (double)Long.MAX_VALUE, there's not enough precision in double type to represent it, so the closest representable value is selected which is 9223372036854775808.0 (Long_MAX_VALUE+1.0). So were it d <= Long.MAX_VALUE it would return true for number which is actually a little bigger as in this comparison Long.MAX_VALUE constant is promoted to double type. On the other hand Long.MIN_VALUE can be exactly represented in double type, thus here we have >=.
Also it's interesting why the following works:
double value = -9223372036854775809.9; // Long.MIN_VALUE-1.9
System.out.println(fitsLong(value)); // returns true
That's because you actually did not subtract anything from the Long.MIN_VALUE. See:
double d1 = Long.MIN_VALUE;
double d2 = -9223372036854775809.9;
System.out.println(d1 == d2); // true
The double precision is not enough to distinguish between -9223372036854775808 and -9223372036854775809.9, so it's actually the same double number. During the compilation it's converted to binary form, and binary form for these two numbers is the same. Thus having compiled program you cannot distinguish whether -9223372036854775808 or -9223372036854775809.9 was in the source code.
If you feel that it's still the issue, construct the BigDecimal from the String:
long l = new BigDecimal("-9223372036854775808.2")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ok, -9223372036854775808
long l = new BigDecimal("-9223372036854775808.9")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
When you cast a floating point type to an int or long, the result is either the nearest integer (rounding towards zero), or the MIN_VALUE or MAX_VALUE for int or long. See JLS 5.1.3.
Hence, one alternative would be to do the typecast and then test for the appropriate MIN_VALUE or MAX_VALUE.
Note that Long.MAX_VALUE is 9223372036854775807 ... which is the number your test program outputs!
(However, this doesn't work if you are casting a floating point type to byte, char or short. See the link above for the explanation.)
I would like to initialize a double directly by using the hexadecimal-notation. I know this works for int and Long as shown in the following example (resulting values always right):
int i = 0x10000000; // 268435456
Long li = 0x1000000000000000L; // 1152921504606846976
On the other hand, if I try do the same with doubles, it works but only in range of 4 Bytes (view comments in the code example). For the second, not valid notation the Netbeans IDE keeps telling me that is is an integer value and, thus, too large:
double d1 = 0x10000000; // 2.68435456E8
double d2 = 0x1000000000000000; // not valid
float-values work as well as they are in the range of 4 Bytes:
float f1 = 0x10000000; // 2.68435456E8
Is there a way to directly write/initialize a double with hexadecimal-notation?
Is the only reason for being able to write a Long with hex-notation that there is no "L" in this notation (in contrast to "f" for float or the not valid "." for marking doubles)?
Why is there a limitation to 4 Bytes? And why does it apply to double and not to Long?
Thank you for your advise and suggestions.
Java supports floating-point hexadecimal literals since 1.5
double d = 0x1f.1p1;
If you just want to initialize your double with an integer value in the long range, use:
double d2 = 0x1000000000000000L;
You can also supply integer hexadecimal values outside the long range using BigInteger:
double d3 = new BigInteger("123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0", 16).doubleValue();
If you need to supply hexadecimal fractions, as suggested in the previous answer, use a hexadecimal floating point literal:
double d = 0x1F.1p1;
I was doing some stuff with palindromes:
This number 9966006699 has been giving me problems. It's a product of 99979 and 99681
99979 * 99681 = 9966006699
I ran that in PHP
$i = 99979 * 99681;
echo $i;
var_dump($i);
Outputs
9966006699 float(9966006699)
So in PHP the product is obviously a float data type. But in Java it's different as seen below :
This
public static void main(String[] args) {
float f = 99979 * 99681;
System.out.println(f);
long o = 99979 * 99681;
System.out.println(o);
double d = 99979 * 99681;
System.out.println(d);
int i = 99979 * 99681;
System.out.println(i);
}
Outputs
1.37607206E9
1376072107
1.376072107E9
1376072107
Google's calculator gives the right thing
I'm lost, why is Java giving the wrong output? and Does it have anything to do with the E9 stuff behind the float and double types? Help. Thanks
The numbers 99979 and 99681 are both int's. The multiplication expression is therefore an int expression too. The maximum value of an int expression is 2147...... Your value 9966006699 is way above that. Hence you have fallen in the realms of the strange behaviour that you get from modulo-n arithmetic. (That is, you have fallen victim to the C-family languages' version of the Y2K problem.)
Try this :
long o = (long)99979 * 99681;
System.out.println(o);
It looks like integer overflow as 9 966 006 699 > Integer.MAX_INT = 2 147 483 647. As int times int have type int the result overflows. Then it is cast to int/float/long etc.
This should be correct (for non-int):
long value = (long)99979 * (long)99681
Alternativly you can use BigInteger class which:
May be slower the using int/long
Don't have this problem for any numbers (long just moves the problem from 2^31 - 1 to 2^63-1).
Integer.MAX_VALUE is equal to 2^31-1, which is smaller than the number you're dealing with, so you're essentially getting integer overflow issues. You can get around this by using a long, or the BigInteger class.
You can read about the numeric limits of primitive data types here:
http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html