3

I have on question regarding double precision.When a float value is passed into double then I get some different result. For e.g.

float f= 54.23f;
double d1 = f;
System.out.println(d1);

The output is 54.22999954223633. Can someone explain the reason behind this behaviour. Is it like double defaults to 14 places of decimal precision.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Hitesh
  • 703
  • 1
  • 9
  • 14

5 Answers5

6

The same value is printed differently for float and double because the Java specification requires printing as many digits as needed to distinguish the value from adjacent representable values in the same type (per my answer here, and see the linked documentation for more precision in the definition).

Since float has fewer bits to represent values, and hence fewer values, they are spaced more widely apart, and you do not need as many digits to distinguish them. When you put the value into a double and print it, the Java rules require that more digits be printed so that the value is distinguished from nearby double values. The println function does not know that the value originally came from a float and does not contain as much information as can fit into a double.

54.23f is exactly 54.229999542236328125 (in hexadecimal, 0x1.b1d70ap+5). The float values just below and just above this are 54.2299957275390625 (0x1.b1d708p+5) and 54.23000335693359375 (0x1.b1d70cp+5). As you can see, printing “54.229999” would distinguish the value from 54.229995… and from 54.23…. However, the double values just below and just above 54.23f are 54.22999954223632101957264239899814128875732421875 and 54.22999954223633523042735760100185871124267578125. To distinguish the value, you need “54.22999954223633”.

Community
  • 1
  • 1
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • One reason I really dislike implicit `float` to `double` conversions is that even though, from a bit-level perspective, something like 0x1.B1D708A+5 is a perfect representation of a power-of-two fraction, floating-point variables are more typically *used* as imperfect representations for numbers which are not power-of-two fractions. If I know that the closest `float` to some number is 0x1.B1D708A+5, that will imply that the number is within a certain range, but should be considered indistinguishable from other values within that range. Converting that to `double`... – supercat Sep 04 '13 at 07:23
  • ...will falsely assume and imply that the number the variable was intended to represent was very near the center of the range of numbers the `float` could represent, even though in practice there was likely no plausible basis for that assumption. Regarding 16777217f and 16777216.0001 as ranking equally would IMHO be less evil than regarding the former value as ranking lower (which is what will happen if comparison operators implicitly convert both operands to `double`). – supercat Sep 04 '13 at 07:28
  • This is an improper use. Neither a `float` nor a `double` can carry any information about an interval around it. It represents a single number. Some people imagine it represents an interval up to, say, the midpoints of the neighboring values. However, this can be true only if a single operation has been performed, such as conversion from decimal to binary floating-point. After more than one operation, the error may be larger, and there is no bound on how it may grow. Therefore, if interval information is to be represented, it must be carried in separate data.… – Eric Postpischil Sep 05 '13 at 15:04
  • … Then a conversion from `float` to `double` is irrelevant, since it changes neither the converted value nor the separate data. Proper computing as achieved by conforming to specifications, not by using floating-point in ways known to be incorrect. The Java default display of a floating-point value should be used only as an indication of the value, not as an indication of accuracy or an interval. – Eric Postpischil Sep 05 '13 at 15:05
  • Of course most floating-point numbers resulting from multi-step calculations generally deviate from perfectly-computed value by an amount much greater than the error interval would suggest, but most `double` computations don't have enough steps or sufficiently catastrophic cancellation to push the error out to 2^29ulps, which would be the *starting* point for a `double` that's cast from a `float`. Further, something like a floating-point literal should qualify as the "result of a single operation of precise operands". – supercat Sep 05 '13 at 16:10
  • Given `const double scale1=3.1; const float scale2=5.7f; float f; double d;`, consider what meanings could be intended by `f=scale1;` or `d=scale2;`. I can't think of any value a programmer might plausibly have intended to load into `f` other than the `float` nearest to 3.1. Can you? By contrast, in the latter situation, I would consider it not just plausible, but *likely*, that the programmer wanted to load the `double` closest to 5.7, but the constant was defined with an `f` so `scale2` could be assigned to `float` values. Would you think it more likely the programmer wants 5.7 or 5.7f? – supercat Sep 05 '13 at 16:19
  • @supercat: I disagree that this code definitively indicates those intents. But I work with people who are familiar with the IEEE 754 standard and write very precise (sometimes proven) floating-point code for special purposes. `f=scale1` might be part of a head-tail extraction from the `double`, intended to get the `float` nearest the `double`, not the `float` nearest 3.1. With `d=scale2`, it may be that `float` is used for storage but calculating can use `double`. Programmers should express intent through comments and other documentation, not sloppy use of code. – Eric Postpischil Sep 05 '13 at 16:44
  • Languages should be designed IMHO to minimize "yes that's what I want" stuff when a programmer's intent unambiguously matches behavior, and require it when intent is *reasonably likely to differ significantly*. Given `d=f1+f2;` it's plausible the programmer wants the addition performed as `float` for speed, but I'd consider it equally likely that the programmer was expecting (and intended) a C-style promotion to `double`. What I'd consider most helpful would be a language with two compile-time `float` types: one whose behavior mimics `C`, and one with no implicit conversions. – supercat Sep 05 '13 at 17:06
  • If I were writing code which is trying to make very careful use of 32-bit floats and relies upon to them to precisely match the standard, I'd regard *any* implicit floating-point conversions as *probable* mistakes and want the compiler to flag them all. When writing code which uses 32-bit floats because they're smaller than `double` and accurate "enough", however, I'd rather have the compiler's behavior be more in line with that intention. Allowing different behaviors for different usage cases could improve both. – supercat Sep 05 '13 at 17:15
  • @supercat: How a language should be designed is not relevant to this floating-point topic. – Eric Postpischil Sep 05 '13 at 17:54
0

This is because the float hides the extra decimals and double shows them. The double will represent the actual number quite precisely and shows more digits.

Try this:

System.out.println(f.doubleValue()); (need to make it a Float first ofcourse)

So as you can see, the information is there, it is just rounded. Hope this helps

Are
  • 179
  • 1
  • 3
  • 16
  • It is likely that `f.doubleValue()` is implemented as `new Double(f)`. – OldCurmudgeon Mar 21 '13 at 13:49
  • @OldCurmudgeon, it is a cast. `return (double)value;` – jn1kk Mar 21 '13 at 13:51
  • 1
    This is close, but it is not complete. Printing a `double` does not always show more precision; sometimes it shows the same result as printing the same value in `float`. The actual rule is that the numeral printed must be such that the value that was passed for printing is the value in the type nearest to the value of the numeral (with some addition rules about ties). This often results in `double` displaying with more digits than `float`, but not always. – Eric Postpischil Mar 21 '13 at 15:05
0

This is due to the Internal Representation.
Floating-point numbers are typically packed into a computer datum as the sign bit, the exponent field, and the significand (mantissa), from left to right.

This is called as Accuracy Problems.
The fact that floating-point numbers cannot precisely represent all real numbers, and that floating-point operations cannot precisely represent true arithmetic operations, leads to many surprising situations. This is related to the finite precision with which computers generally represent numbers.

It is not a problem. It is how double works. You do not have to handle it and care about it. The precision of double is enough. Think, the difference between you number and the expected result is in the 14 position after decimal point.

If you need arbitrarily good precision, use the java.math.BigDecimal class.

Or if you still want to use double. Do like this:

double d = 5.5451521841;
NumberFormat nf = new DecimalFormat("##.###");
System.out.println(nf.format(d));

Please let me know in case of any doubt.

Shreyos Adikari
  • 12,348
  • 19
  • 73
  • 82
  • I do not believe the question was about why `54.23f` does not have the value 54.23 but about why printing it as a `double` shows more digits than printing it as a `float` even though the same value is printed. – Eric Postpischil Mar 21 '13 at 15:06
0

Actually this is only about different visual representation or converting float / double to String. Let's take a look at internal binary representation

    float f = 0.23f;
    double d = f;
    System.out.println(Integer.toBinaryString(Float.floatToIntBits(f)));
    System.out.println(Long.toBinaryString(Double.doubleToLongBits(d)));

output

111110011010111000010100011111
11111111001101011100001010001111100000000000000000000000000000

it means that f was converted to d1 without any distortion, significant digits are the same

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
-1

double and float represent numbers in different formats.

Because of this you are bound to find certain numbers that store perfectly in one format but not in the other. You happen to have found one that correctly fits in a float but does not fit exactly in a `double.

This problem can also show itself when two different formatters are used.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • 4
    A `double` uses the same basic format as a `float`, it just uses more bits. Every `float` value should be representable exactly as a `double`. – Joachim Sauer Mar 21 '13 at 13:53
  • @JoachimSauer: For every `float`, there exists a `double` with the same nominal value, but floating-point numbers have meaning beyond the nominal value. Consider the following questions: "Will a 3.0cm peg fit in a 3.002cm hole?" and "Will a 3.000cm peg fit in a 3.002cm hole?" Both pegs have exactly the same nominal size, but the latter peg is specified to fit and the former one isn't (even if it were 3.004cm it could still be described as a 3.0cm peg). There is no `double` value with the same "meaning" as any `float` value; for two values in particular, no `double` is even close. – supercat Jul 25 '13 at 23:38