I was reading a book about Java and I found the following points unclear, please help me:
For integer literal expressed in any base other than base 10 (0b, 0, 0x) can we use the L suffix that stands for Long?
For floating point can we use any other base other than decimal? If yes can we specify float or double using F or D for other bases other than 10?
If yes with other bases than 10 could we use scientific notation or only decimal point is allowed?
1) Yes, it's possible for hexadecimal, octal and binary too. See jls-3.10.1
2) Yes, you can use hexadecimal notation, but you are restricted to binary exponents and specifying the exponent is required. See jls-3.10.2
Examples:
0xFF.Ap0d
0xFF.1p0f
0xFF.Ap1d
0xFF.Ap-1f
0xFF.Ap-1
0x.1p16
If you print these literals using System.out.println, you get:
255.625
255.0625
511.25
127.8125
63.90625
4096.0
The meaning of the binary exponent is as follows:
The value in front of the p or P is multipled by 2^z where z is the integer after the p (or P). The integer is in decimal format. E.g. 0xFF.1Ap0101d stands for 255.1015625 * 2^101.
Related
I understand that the theory of binary numbers, so operation of double numbers is not precise. However, in java, I have no idea why "(double)65 / 100" is 0.65, which is completely correct in decimal number, other than 0.6500000000004.
double a = 5;
double b = 4.35;
int c = 65;
int d = 100;
System.out.println(a - b); // 0.6500000000000004
System.out.println((double) c / d); // 0.65
Java completely messes up has its own way of handling floating-point binary to decimal conversions.
A simple program in C (compiled with gcc) gives the result:
printf("1: %.20f\n", 5.0 - 4.35); // 0.65000000000000035527
printf("2: %.20f\n", 65./100); // 0.65000000000000002220
while Java gives the result (note you only needed 17 digits to see it, but I'm trying to make it more clear):
System.out.printf("%.20f\n", 5.0 - 4.35); // 0.65000000000000040000
System.out.printf("%.20f\n", 65./100); // 0.65000000000000000000
But when using the %a format specifier, both languages printf the underlying hexadecimal (correct) value: 0x1.4ccccccccccd00000000p-1.
So, Java is performing some illegal rounding at some point in the code. The apparent issue here is that Java has a different set of rules to convert binary to decimal, from the Java specification:
The number of digits in the result for the fractional part of m or a is equal to the precision. If the precision is not specified then the default value is 6. If the precision is less than the number of digits which would appear after the decimal point in the string returned by Float.toString(float) or Double.toString(double) respectively, then the value will be rounded using the round half up algorithm. Otherwise, zeros may be appended to reach the precision. For a canonical representation of the value, use Float.toString(float) or Double.toString(double) as appropriate. (emphasis mine)
And in the toString specification:
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0. (emphasis mine)
So, Java does perform a different binary to decimal conversion from C, but it remains closer to the true binary value than to any other, so the spec guarantees that the binary value can be restored back by a decimal to binary conversion.
Professor William Kahan warned about some Java floating-point issues in this article:
How Java’s Floating-Point Hurts Everyone Everywhere
But this conversion behaviour seems to be IEEE-complaint.
EDIT: I have included information provided by #MarkDickinson in the comments, to report that this Java behaviour, albeit different from C, is documented, and is IEEE-compliant. This has already been explained here, here, and here.
System.out.println(2e+5);
Above line's output is,
200000.0
While below line's,
System.out.println(2e-5);
output is,
2.0e-5
Why does 2e-5 is not solved down with -10^5 giving the output,
0.00002
Because that's how the designers of the Double class chose to implement it:
[...]
If m is greater than or equal to 10-3 but less than 107, then it is represented as the integer part of m, in decimal form with no leading zeroes, followed by '.' ('\u002E'), followed by one or more decimal digits representing the fractional part of m.
If m is less than 10-3 or greater than or equal to 107, then it is represented in so-called "computerized scientific notation." [...]
They could have made another choice, of course, but that's simply how it is.
As the documentation says, if you want a specific format, use a NumberFormat to format your double.
As already pointed out by #Nizet, when converting double to string, the output will have scientific notation if number of digits are large. And this is not just for decimals.
Consider:
double d = 1500000000;
System.out.println(String.valueOf(d));
This will print 1.5E9
If you want conversion to happen in readable format, use String.format
System.out.println(String.format ("%.0f", d));
will print 1500000000
This question already has answers here:
Declaring floats, why default type double?
(3 answers)
Closed 6 years ago.
Ok I got a couple values here:
'F', 0xf, 070, 70L, 77e-1f, 7.7f, 7.77e1, 77.7
I know that 'F' is a char and that 70L has the type long. Also, I know that 0xf is hex(right?) and that 070 is octal. But what are those other numbers? And why the hell is 77.7 double and not float as well?
What you're looking for is this
About 77.7:
A floating-point literal is of type float if it ends with the letter F
or f; otherwise its type is double and it can optionally end with the
letter D or d.
0xf is not of type hex. There is no type hex. It's simply an int wirtten in hex. Just like 070 is an int written in octal.
The literal 77e-1fis clearly a float since it ends with f.
The e is exponent i.e. 77e-1f is in fact 77 * 10^(-1) or 7.7. The literal 7.77e1 is a double for the same reason 77.7 is a double, it's just that 7.77e1 is equal to 7.77 * 10 ^ 1 = 77.7.
In Java numerical literals that contain a dot are of type double by default. If you want a float, you neef to append the f.
The numbers containing the e are in exponential or scientific notation, but I am not going to explain it here because it has nothing to do with programming.
The only two which you didn't explain yourself:
7.7f
That f means float - it indicates that this should not be a double literal, but well, a float one! You see, by default any "floating point" literals are automatically of type double, you need the "f" in order to enforce the "smaller" float type.
And
77e-1f
is using scientific notation, see here for example for further explanations.
77e-1 means this: 77 is number-multiplier, e (or E) means base 10, and -1 means exponent.
So the result is 77 by (10 powered by -1), or 77 by .1, i. e. 7.7
The name of this notation is scientific or logarithmic and is good for very large or very small numbers, e. g. 1 million = 1.000.000 may be expressed as 1e6
And why the hell is 77.7 double and not float as well?
Float numbers has to be denoted with f on the end but double numbers don't require d on the end.
77e-1f is a float number 77 to the power of 10^-1, so it equals 7.7.
The same with 7.77e1 == 77.7
I'm doing some large number divisions (long/long to double, and int/int to float).. But I bump, to a problem when the results include the "E". I know we can use NumberFormat to format when displaying, but that's not what I. Just want the result of the divisions to not involve the "E", i.e. just round it up to the closest float/double that fits in the space.
Anybody got an idea?
The internal representation of floating point number does not have a switch for E presence or not (check IEEE-754). So your float/double number is just number (not a number with E or without it).
The only place where you get E is when you print this value out. And while Java uses number formater for printing, so I don't see a point why you don't want to use it here.
System.out.println(new DecimalFormat("#.#####").format(doubleValue));
The general problem that double and float in binary format. It not always possible to convert decimal fraction to binary fraction. For example 0.2 decmal fraction have infinitely many digits in binary (double) format. So whe converted from bynary format to decimal string, it result something like "0.2000000001" what displayed with E. To solve this problem you can use BigDecimal class what contains number in decimal format, so no E problem - it can easy rounded to any decimal point by setScale method. Or you can sore double as is, an write it to output by String.format("My value are: %.3f", value) - i recommend this way.
If you just want round you value to decimal point you can use:
new BigDecimal(val).setScale(3, RoundingMode.HALF_EVEN).doubleValue()
But there no any garanty what this core return double with fine fraction numbers.
Why does 0x1p3 equal 8.0? Why does 0x1e3 equal 483, whereas 0x1e3d equals 7741? It is confusing since 1e3d equals 1000.0.
0x1e3 and 0x1e3d are hexadecimal integer literals. Note that e and d are hexadecimal digits, not the exponent indicator or double type indicator in this case.
1e3d is a decimal floating-point literal. The e is the exponent indicator, the d says that this is a double rather than a float.
The notation 0x1p3 is a way to express a floating-point literal in hexadecimal, as you can read in section 3.10.2 of the Java Language Specification. It means 1 times 2 to the power 3; the exponent is binary (so, it's 2-to-the-power instead of 10-to-the-power).
0x1e3 is hex for 483, as is 0x1e3d hex for 7741. The e is being read as a hex digit with value 14.