Displayed precision of Java floating-point - java

If we run the following code:
float f = 1.2345678990922222f;
double d = 1.22222222222222222222d;
System.out.println("f = " + f + "\t" + "d = " + d);
it prints:
f = 1.2345679 d = 1.2222222222222223
The long tail in the literal 1.2345678990922222 is ignored but the long tail in 1.22222222222222222222 is not (the last decimal digit in the variable d becomes 3 instead of 2). Why?

The number of digits you see when a float or a double is printed is a consequence of Java’s rules for default conversion of float and double to decimal.
Java’s default formatting for floating-point numbers uses the fewest significant decimal digits needed to distinguish the number from nearby representable numbers.1
In your example, 1.2345678990922222f in source text is converted to the float value 1.2345678806304931640625, because, of all the values representable in the float type, that one is closest to 1.2345678990922222. The next lower and next higher values are 1.23456776142120361328125 and 1.23456799983978271484375.
When printing this value, Java only needs to print “1.2345679”, because that is enough that we can pick out the float value 1.2345678806304931640625 from its neighbors 1.23456776142120361328125 and 1.23456799983978271484375.
For your double example, 1.22222222222222222222d is converted to 1.22222222222222232090871330001391470432281494140625. The next lower and next higher values representable in double are 1.2222222222222220988641083749826066195964813232421875 and 1.2222222222222225429533182250452227890491485595703125. As you can see, to distinguish 1.22222222222222232090871330001391470432281494140625 from its neighbors, Java needs to print “1.2222222222222223”.
Footnote
1 The rule for Java SE 10 can be found in the documentation for java.lang.float, in the toString(float d) section. The double documentation is similar. The passage, with the most relevant part in bold, is:
Returns a string representation of the float argument. All characters mentioned below are ASCII characters.
If the argument is NaN, the result is the string "NaN".
Otherwise, the result is a string that represents the sign and magnitude (absolute value) of the argument. If the sign is negative, the first character of the result is '-' ('\u002D'); if the sign is positive, no sign character appears in the result. As for the magnitude m:
If m is infinity, it is represented by the characters "Infinity"; thus, positive infinity produces the result "Infinity" and negative infinity produces the result "-Infinity".
If m is zero, it is represented by the characters "0.0"; thus, negative zero produces the result "-0.0" and positive zero produces the result "0.0".
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." Let n be the unique integer such that 10n ≤ m < 10n+1; then let a be the mathematically exact quotient of m and 10n so that 1 ≤ a < 10. The magnitude is then represented as the integer part of a, as a single decimal digit, followed by '.' ('\u002E'), followed by decimal digits representing the fractional part of a, followed by the letter 'E' ('\u0045'), followed by a representation of n as a decimal integer, as produced by the method Integer.toString(int).
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 float. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument f. Then f must be the float value nearest to x; or, if two float values are equally close to x, then f must be one of them and the least significant bit of the significand of f must be 0.

Related

After converting bits to Double, how to store actual float/double value without using BigDecimal?

According to several floating point calculators and as well as my code below, the following 32 bits 00111111010000000100000110001001 has an actual Floating Point value of (0.750999987125396728515625). Since it is the actual Float value, I should think storing it in a Double or Float would retain the precision and exact value so long as (1) no arithmetic is performed (2) the actual value is used and (3) the value is not down-casted. So why is the actual value different from the casted (example 1) and literal (example 2) value of (0.7509999871253967)?
I used this calculator as an example:
https://www.h-schmidt.net/FloatConverter/IEEE754.html
import java.math.BigInteger;
import java.math.BigDecimal;
public class MyClass {
public static void main(String args[]) {
int myInteger = new BigInteger("00111111010000000100000110001001", 2).intValue();
Double myDouble = (double) Float.intBitsToFloat(myInteger);
String myBidDecimal = new BigDecimal(myDouble).toPlainString();
System.out.println(" bits converted to integer: 00111111010000000100000110001001 = " + myInteger);
System.out.println(" integer converted to double: " + myDouble);
System.out.println(" double converted to BigDecimal: " + myBidDecimal);
Double myDouble2 = 0.750999987125396728515625;
String myBidDecimal2 = new BigDecimal(myDouble2).toPlainString();
System.out.println("");
System.out.println(" Ignore the binary string: ");
System.out.println(" double from literal: " + myDouble2);
System.out.println(" double converted to BigDecimal: " + myBidDecimal2);
}
}
Here is the output:
bits converted to integer: 00111111010000000100000110001001 = 1061175689
integer converted to double: 0.7509999871253967
double converted to BigDecimal: 0.750999987125396728515625
Ignore the binary string:
double from literal: 0.7509999871253967
double converted to BigDecimal: 0.750999987125396728515625
There is no actual loss of precision; the issue is your incorrect expectations about how doubles are converted to String (e.g. when printed).
From the documentation of Double.toString:
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.
So when a double gets printed, it is printed only with enough digits to uniquely identify that double value, not with the number of digits needed to describe the precise value as a real number.
If you want to get the precise value of a double with all possible digits, new BigDecimal(theDouble).toPlainString() is how you do it -- and, as you demonstrate, it gets the correct result.

The width of a double variable

I am trying to write some text to a file using PrintWriter and I do not understand what "7" means in the next example:
double d = 12.11211;
out.format(“%7.3f”, d);
The source from where I am inspiring says that 7 means:
The 7.3 before the f denotes the width (7) and precision (3) to output
d in.
The problem is that I cannot understand what that width really means. I mean, even though my variable would have more than 7 digits, it is not going to format anything.
Think of it as the total length of the string produced by the applied format.
If you take in account that there will be exactly 3 chars after the decimal point and 1 char for the decimal point itself, then it leaves 3 chars for the integer part.
Because your number has only 2 digits in the integer part the final result will be padded at the left with a white space:
double d = 12.11211;
out.format("%7.3f", d);
will create:
" 12.112"
with
out.format("%8.3f", d);
you get
" 12.112"
and so on.
The minimum length of the formatted string is in your case:
6 = 2 chars for the integer part + 1 char for the decimal point + 3 chars for the digits after the decimal point
so even if you set:
out.format("%5.3f", d);
this will not truncate the result, it will be:
"12.112"
For simple text arguments, you can think of the width and precision as a minimum and maximum number of characters to be output. For floating-point numeric types, the precision changes meaning slightly and controls the number of digits displayed after the decimal point.
watch this example:
System.out.printf("String is '%5s'\n", "A");
// String is ' A'
System.out.printf("String is '%.5s'\n", "Happy Birthday!");
// String is 'Happy'
for more information look at this link
Your source of inspiration should be the javadoc. It says:
The width is the minimum number of characters to be written to the
output. If the length of the converted value is less than the width
then the output will be padded by ' ' ('\u0020') until the total
number of characters equals the width. The padding is on the left by
default.[...]
For the floating-point conversions 'a', 'A', 'e', 'E', and 'f' the precision is the number of digits after the radix point.
A simple experiment shows it:
System.out.printf("%7.3f%n", 1.3);
System.out.printf("%7.3f%n", 12.3);
System.out.printf("%7.3f%n", 12.34);
System.out.printf("%7.3f%n", 12.345);
System.out.printf("%7.3f%n", 12.3456);
System.out.printf("%7.3f%n", 12.34567);
System.out.printf("%7.3f%n", 12.34567);
System.out.printf("%7.3f%n", 123.34567);
System.out.printf("%7.3f%n", 1234.34567);
System.out.printf("%7.3f%n", 12345.34567);
prints:
1,300
12,300
12,340
12,345
12,346
12,346
12,346
123,346
1234,346
12345,346
By width, it means the string will always fill the rest of the places if the number of digits/characters of the value is less than the given number.
double d = 12.11211;
String.format(“%7.3f”, d);
> 12.112
^^^^^^^
1234567
According to this:
The field width in a formatting operator is a nonnegative integer that
specifies the number of digits or characters in the output when
formatting input values. For example, in the operator %7.3f, the field
width is 7.
By default, the output text is padded with space
characters when the field width is greater than the number of
characters.
The 7 adds padding () in case the output is smaller than 7 characters. This way the output is always at least 7 characters, with 3 floating decimals.
This documentation gives a very detailed explanation for formatting text in general, most of which is applicable cross-language.

why program can exactly display infinite repeating floating point number in java or other language

like a decimal number 0.1, represented as binary 0.00011001100110011...., this is a infinite repeating number.
when I write code like this:
float f = 0.1f;
the program will rounding it as binary 0 01111011 1001 1001 1001 1001 1001 101, this is not original number 0.1.
but when print this variable like this:
System.out.print(f);
I can get original number 0.1 rather than 0.100000001 or some other number. I think the program can't exactly represent "0.1", but it can display "0.1" exactly. How to do it?
I recover decimal number through add each bits of binary, it looks weird.
float f = (float) (Math.pow(2, -4) + Math.pow(2, -5) + Math.pow(2, -8) + Math.pow(2, -9) + Math.pow(2, -12) + Math.pow(2, -13) + Math.pow(2, -16) + Math.pow(2, -17) + Math.pow(2, -20) + Math.pow(2, -21) + Math.pow(2, -24) + Math.pow(2, -25));
float f2 = (float) Math.pow(2, -27);
System.out.println(f);
System.out.println(f2);
System.out.println(f + f2);
Output:
0.099999994
7.4505806E-9
0.1
in math, f1 + f2 = 0.100000001145... , not equals 0.1. Why the program would not get result like 0.100000001, I think it is more accurate.
Java's System.out.print prints just enough decimals that the resulting representation, if parsed as a double or float, converts to the original double or float value.
This is a good idea because it means that in a sense, no information is lost in this kind of conversion to decimal. On the other hand, it can give an impression of exactness which, as you make clear in your question, is wrong.
In other languages, you can print the exact decimal representation of the float or double being considered:
#include <stdio.h>
int main(){
printf("%.60f", 0.1);
}
result: 0.100000000000000005551115123125782702118158340454101562500000
In Java, in order to emulate the above behavior, you need to convert the float or double to BigDecimal (this conversion is exact) and then print the BigDecimal with enough digits. Java's attitude to floating-point-to-string-representing-a-decimal conversion is pervasive, so that even System.out.format is affected. The linked Java program, the important line of which is System.out.format("%.60f\n", 0.1);, shows 0.100000000000000000000000000000000000000000000000000000000000, although the value of 0.1d is not 0.10000000000000000000…, and a Java programmer could have been excused for expecting the same output as the C program.
To convert a double to a string that represents the exact value of the double, consider the hexadecimal format, that Java supports for literals and for printing.
I believe this is covered by Double.toString(double) (and similarly in Float#toString(float)):
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.
(my emphasis)

What are the Java primitive data type modifiers?

Alright, I've been programming in Java for the better part of three years, now, and consider myself very experienced. However, while looking over the Java SE source code, I ran into something I didn't expect:
in class Double:
public static final double MIN_NORMAL = 0x1.0p-1022; // 2.2250738585072014E-308
public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324
I did not expect this and can't find out what it means. If you don't know, I'm referring to the p and P that are after these numbers, before the subtraction operator. I know you can use suffixes to force a number to be a double, long, float, etc., but I've never encountered a p or P. I checked the Java API, but it doesn't mention it. Is there a complete list of Java primitive number literal modifiers somewhere? Does anyone know them all?
For reference, below are the ones I've used or encountered, with the ones whose purposes elude me in bold with question marks (# represents any arbitrary number within respective limits):
Suffixes:
# = 32-bit integer int
#L = 64-bit integer long
#l = another 64-bit integer l?
#f = 32-bit floating-point float
#F = another 32-bit floating-point float?
#d = 64-bit floating-point double
#D = another 64-bit floating-point double?
#e# = scientific notation
#E# = another scientific notation?
#p = ?
#P = ?
Any more?
Prefixes:
0b# = binary (base 2) literal
0B# = another binary (base 2) literal?
0# = octal (base 8) literal
# = decimal (base 10) literal
0x# = hexadecimal (base 16) literal
0X# = another hexadecimal (base 16) literal?
Any more?
Other (are there suffixes or prefixes for these?):
(byte)# = 8-bit integer byte
(short)# = 16-bit integer short
(char)# - 32-bit character char
P is the exponent. It does not matter if it's capital or not.
According to the Javadoc for toHextString (which we know is being used because it begins with 0x:
public static String toHexString(double d) Returns a hexadecimal string representation of the double argument. All characters mentioned below are ASCII characters. If the argument is NaN, the result is the string "NaN". Otherwise, the result is a string that represents the sign and magnitude of the argument. If the sign is negative, the first character of the result is '-' ('\u002D'); if the sign is positive, no sign character appears in the result. As for the magnitude m:
If m is infinity, it is represented by the string "Infinity"; thus, positive infinity produces the result "Infinity" and negative
infinity produces the result "-Infinity".
If m is zero, it is represented by the string "0x0.0p0"; thus, negative zero produces the result "-0x0.0p0" and positive zero produces the result "0x0.0p0".
If m is a double value with a normalized representation, substrings are used to represent the significand and exponent fields. The significand is represented by the characters "0x1." followed by a lowercase hexadecimal representation of the rest of the significand as a fraction. Trailing zeros in the hexadecimal representation are removed unless all the digits are zero, in which case a single zero is used. Next, the exponent is represented by "p" followed by a decimal string of the unbiased exponent as if produced by a call to Integer.toString on the exponent value.
If m is a double value with a subnormal representation, the significand is represented by the characters "0x0." followed by a hexadecimal representation of the rest of the significand as a fraction. Trailing zeros in the hexadecimal representation are removed. Next, the exponent is represented by "p-1022". Note that there must be at least one nonzero digit in a subnormal significand.
According to the JLS, the following pieces of grammar are accepted:
3.10.1. Integer Literals
IntegerTypeSuffix:
l
L
OctalNumeral:
0 OctalDigits
0 Underscores OctalDigits
HexNumeral:
0 x HexDigits
0 X HexDigits
BinaryNumeral:
0 b BinaryDigits
0 B BinaryDigits
3.10.2. Floating-Point Literals
ExponentIndicator: one of
e
E
FloatTypeSuffix: one of
f
F
d
D
HexSignificand:
HexNumeral
HexNumeral .
0 x HexDigitsopt . HexDigits
0 X HexDigitsopt . HexDigits
BinaryExponentIndicator: one of
p
P
No other single character literals are specified for those purposes.
All of the legal ways to declare a literal are defined in the JLS.
p or P is the binary exponent of a number.
l or L defines a long.
f or F defines a float.
d or D defines a double.
0B or 0b defines a binary literal.
0x or 0X defines a hexadecimal literal.
e or E is also an exponent, but since e is a valid character in hexadecimal, p is also used.
P or p is a BinaryExponentIndicator. See the Java language specification.
See http://docs.oracle.com/javase/specs/jls/se5.0/html/lexical.html#3.10.2

How to prevent scientific display of a float?

I have the following output
output =4.08E-4
output =8.9E-5
output =0.978461
output =0.224577
Now the thing I don't get is for 4.08E-4 - I assume it is a negative exponential and given <0 it returns true but is there another way of displaying this in decimal format?
Most likely you are trying to print a float/double using System.out.println(...).
This eventually calls the public static String toString() method of Float (or Double). Either way, if you read the Javadoc it states:
If m is less than 10-3 or greater than or equal to 107, then it is
represented in so-called "computerized scientific notation." Let n be
the unique integer such that 10n <= m < 10n+1; then let a be the
mathematically exact quotient of m and 10n so that 1 <= a < 10. The
magnitude is then represented as the integer part of a, as a single
decimal digit, followed by '.' ('\u002E'), followed by decimal digits
representing the fractional part of a, followed by the letter 'E'
('\u0045'), followed by a representation of n as a decimal integer, as
produced by the method Integer.toString(int).
You can get around this using System.out.printf(), like this:
double d = 0.000408;
System.out.println(d);
System.out.printf("%f", d);
This prints:
4.08E-4
0,000408
My 2 cents.
System.out.println(4.08e-4);
0.000408
I use NumberFormat class-
double d = 0.000408;
//For considering 4 digits after decimal place
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(4);
nf.setGroupingUsed(false);
System.out.println(d);
System.out.println(nf.format(d));
I think what you're looking for is either the class NumberFormat or the printf function, either one would work.

Categories

Resources