# When to use float (in teaching)

Discussion in 'Java' started by Stefan Ram, May 7, 2009.

1. ### Stefan RamGuest

I teach some properties of the data type »double«:

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( 0.1 + 0.1 + 0.1 == 0.3 );
java.lang.System.out.println( 1.1 * 1.1 == 1.21 ); }}

false
false

. I also teach that beginners should not use the data type
»float«, because it will only cause trouble.

But now a student came up with this:

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( 0.1f + 0.1f + 0.1f == 0.3f );
java.lang.System.out.println( 1.1f * 1.1f == 1.21f ); }}

true
true

. So, now it looks as if double just does the wrong thing
and as if float just does the right thing.

How does one deal with this, when explaining, when to use
»float« and when to use »double«?

Stefan Ram, May 7, 2009

2. ### Mark ThorntonGuest

Stefan Ram wrote:
> I teach some properties of the data type »double«:
>
> public class Main
> { public static void main( final java.lang.String[] args )
> { java.lang.System.out.println( 0.1 + 0.1 + 0.1 == 0.3 );
> java.lang.System.out.println( 1.1 * 1.1 == 1.21 ); }}
>
> false
> false
>
> . I also teach that beginners should not use the data type
> »float«, because it will only cause trouble.
>
> But now a student came up with this:
>
> public class Main
> { public static void main( final java.lang.String[] args )
> { java.lang.System.out.println( 0.1f + 0.1f + 0.1f == 0.3f );
> java.lang.System.out.println( 1.1f * 1.1f == 1.21f ); }}
>
> true
> true
>
> . So, now it looks as if double just does the wrong thing
> and as if float just does the right thing.

In both cases float and double are working as should be expected. Just
because floating point types often do not represent decimal values
exactly doesn't mean that some values are not represented exactly. In
the case of float the result of 0.1f+0.1f+0.1f is not exactly equal to
0.3 (because 0.3 is not exactly representable by either float or
double). It just happens the nearest float to 0.3 (which is what 0.3f
is) is equal to the result of 0.1f+0.1f+0.1f.

There is a valuable place for the use of float and double in scientific
and engineering computation. Statistics is another area where the use of
floating point is hard to avoid. Outside of these areas they should
mostly be avoided. Unfortunately BigInteger and BigDecimal are bit
tedious to use due to the absence of operator overloading for these types.

Mark Thornton

Mark Thornton, May 7, 2009

3. ### LewGuest

On May 7, 12:15 pm, -berlin.de (Stefan Ram) wrote:
>   I teach some properties of the data type »double«:
>
> public class Main
> { public static void main( final java.lang.String[] args )
>   { java.lang.System.out.println( 0.1 + 0.1 + 0.1 == 0.3  );
>     java.lang.System.out.println(       1.1 * 1.1 == 1.21 ); }}
>
> false
> false
>
>   . I also teach that beginners should not use the data type
>   »float«, because it will only cause trouble.
>
>   But now a student came up with this:
>
> public class Main
> { public static void main( final java.lang.String[] args )
>   { java.lang.System.out.println( 0.1f + 0.1f + 0.1f == 0.3f  );
>     java.lang.System.out.println(        1.1f * 1.1f == 1..21f ); }}
>
> true
> true
>
>   . So, now it looks as if double just does the wrong thing
>   and as if float just does the right thing.

That is a completely deceptive appearance. You just happened to pick
examples that gave that illusion. In reality, both float and double
are doing the right thing, and you cannot count on either one to yield
an exact comparison using '==' with values that are not exactly
representable in finite-precision binary. In reality float has higher
error, because in either case expected error of a term will start at 1
ulp.

>   How does one deal with this, when explaining, when to use
>   »float« and when to use »double«?

One uses double when high precision is required, which is most of the
time. One uses float when high precision is not so necessary, as,
say, Swing does in calculating screen positions, and when speed is
more important than precision.

--
Lew

Lew, May 7, 2009
4. ### Mark ThorntonGuest

Lew wrote:
>
> One uses double when high precision is required, which is most of the
> time. One uses float when high precision is not so necessary, as,
> say, Swing does in calculating screen positions, and when speed is
> more important than precision.
>

Float is used when memory is short, you need a very large number of
values and can tolerate the lower precision. The performance advantage
is modest (and often more a result of fitting more values in the
processor cache than increased speed of the basic operation).
Any exception to this is with GPUs where float is fast but double either
slow or non existent. However this doesn't (yet) apply directly to Java.

Mark Thornton

Mark Thornton, May 7, 2009
5. ### LewGuest

Christian wrote:
> Also a situtation where float is preferred for me to double:
> A volatile float is written atomic  [sic] while a volatile double is not!

That is totally not true.

Volatile doubles are written atomically. JLS 17.7:
> Writes and reads of volatile long and double values are always atomic.

--
Lew

Lew, May 7, 2009
6. ### Mark ThorntonGuest

Lew wrote:
> Christian wrote:
>> Also a situtation where float is preferred for me to double:
>> A volatile float is written atomic [sic] while a volatile double is not!

>
> That is totally not true.
>
> Volatile doubles are written atomically. JLS 17.7:
>> Writes and reads of volatile long and double values are always atomic.

It was true of some early JVMs.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4023233

Note that despite what it says in that bug report, this has been fixed.

Mark Thornton

Mark Thornton, May 7, 2009
7. ### LewGuest

Christian wrote:
>>> Also a situtation where float is preferred for me to double:
>>> A volatile float is written atomic  [sic] while a volatile double is not!

>

Lew wrote:
>> That is totally not true.

>
>> Volatile doubles are written atomically.  JLS 17.7:
>>> Writes and reads of volatile long and double values are always atomic.

>

Mark Thornton wrote:
> It was true of some early JVMs.
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4023233
>
> Note that despite what it says in that bug report, this has been fixed.

That is so 20th century!

Note that the memory model changed significantly (with Java 5) also,
in particular with respect to the semantics of 'volatile'.

I think it's safe to challenge on the basis of the JLS an incorrect
statement about Java semantics irrespective of bugs that were fixed
years and years ago. The point is that Sun's JVM and presumably every
other one extant today conforms to the language specification
regarding atomic reads and writes of volatile longs and doubles.

As Java developers we have to go by the specification, not by bugs in
its implementations. Those that rely on violations of the
specification risk having their code break when the bug is fixed, as,
say, Apache commons-lang did in tbeir "enum" implementation prior to
Java 5 that broke when Sun fixed the bug (and Apache refused to fix
it). Java programmers have a right to expect Java implementations to
conform to the specification.

That is moot here, anyway, since volatile actually works as specified
in this matter: reads and writes of volatile longs and doubles are
atomic. To state otherwise does a huge disservice to those who might
not know better.

--
Lew

Lew, May 7, 2009
8. ### LewGuest

On May 7, 5:40 pm, Lew <> wrote:
> Those that rely on violations of the
> specification risk having their code break when the bug is fixed, as,
> say, Apache commons-lang did in tbeir "enum" implementation prior to
> Java 5 that broke when Sun fixed the bug (and Apache refused to fix
> it).  Java programmers have a right to expect Java implementations to
> conform to the specification.
>

I should clarify: the Apache commons-lang "enum" bug had nothing to do
with 'volatile'. It was that certain methods in their "enum" relied
on references to a 'class' literal causing initialization of the
owning class. When Sun fixed that initialization bug, those Apache
commons "enum" methods broke.

--
Lew

Lew, May 7, 2009
9. ### Mark ThorntonGuest

Lew wrote:
> Christian wrote:
>>>> Also a situtation where float is preferred for me to double:
>>>> A volatile float is written atomic [sic] while a volatile double is not!

>
> Lew wrote:
>>> That is totally not true.
>>> Volatile doubles are written atomically. JLS 17.7:
>>>> Writes and reads of volatile long and double values are always atomic.

>
> Mark Thornton wrote:
>> It was true of some early JVMs.
>>
>> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4023233
>>
>> Note that despite what it says in that bug report, this has been fixed.

>
> That is so 20th century!
>
> Note that the memory model changed significantly (with Java 5) also,
> in particular with respect to the semantics of 'volatile'.
>
> I think it's safe to challenge on the basis of the JLS an incorrect
> statement about Java semantics irrespective of bugs that were fixed
> years and years ago. The point is that Sun's JVM and presumably every
> other one extant today conforms to the language specification
> regarding atomic reads and writes of volatile longs and doubles.
>

Nevertheless, it can be important to check our assumptions. Long ago I
did check for atomic assignment found that it didn't work. Just a few
days ago I found some code that depended on the behaviour of
Timestamp.getTime() as exhibited by JVMs up to 1.4. In 1.4, Sun changed
the behaviour and left the documentation very confusing (especially for
those aware of the previous behaviour).

In this case I was just adding an historical note that there was some
basis for believing the assignments not to be atomic, but today it is
about as valid as suggesting that Java is slow!

Mark Thornton

Mark Thornton, May 7, 2009
10. ### Tom AndersonGuest

On Thu, 7 May 2009, Stefan Ram wrote:

> . I also teach that beginners should not use the data type
> ?float?, because it will only cause trouble.

Interesting. FWIW, i use doubles when i'm doing mathematics, and floats
when i'm doing sums - which is an aphoristic way of saying that i use
doubles when i'm doing calculations where i care about accuracy, range,
etc, whcih is things like numerical work, data processing, whatever, and
floats when i'm doing things like calculating a load factor for a
hashtable, or the index of the 95th centile in an array, etc.

tom

--
When I see a man on a bicycle I have hope for the human race. --
H. G. Wells

Tom Anderson, May 7, 2009
11. ### Stefan RamGuest

Thomas Pornin <> writes:
>The usual rule is the following: compute with the most accurate
>type you have (double) but store only as many bits as are

This sounds good.

However, when float is used to store data, a rank beginner
might be confused with situations, where »3.7 is not 3.7
anymore«:

public class Main
{ public static void main( final java.lang.String[] args )
{ final float a = 3.7f;
java.lang.System.out.println( a == 3.7 ); }}

false

And a rank beginner usually does not need to store very
many floating point values.

Therefore, I deem that in my classes, where I teach to rank
beginners¹ and have very little time, it is appropriate to
recommend not to use float at all. When any of those students
continues to learn Java after the end of my classes he will
eventually learn about when to use »float«.

I asked some years ago, who of them has ever heard the term
»objektorientierte Programmierung« (= »object-oriented
programming«). No hand was raised.

Stefan Ram, May 8, 2009
12. ### Stefan RamGuest

-berlin.de (Stefan Ram) writes:
>However, when float is used to store data, a rank beginner
>might be confused with situations, where »3.7 is not 3.7
>anymore«:

»... confused by situations where ...«

>And a rank beginner usually does not need to store very
>many floating point values.

Another point in teaching is that many beginners tend to
believe that »float« should be used as the standard floating
point type, just because it is /named/ »float«, which is akin
to »floating point«.

Stefan Ram, May 8, 2009
13. ### LewGuest

Mark Thornton wrote:
> Nevertheless, it can be important to check our assumptions. Long ago I
> did check for atomic assignment found that it didn't work. Just a few
> days ago I found some code that depended on the behaviour of
> Timestamp.getTime() as exhibited by JVMs up to 1.4. In 1.4, Sun changed
> the behaviour and left the documentation very confusing (especially for
> those aware of the previous behaviour).

All right, I'll bite. What was the previous behavior, and how did it change
in Java 1.4?

> In this case I was just adding an historical note that there was some
> basis for believing the assignments not to be atomic, but today it is
> about as valid as suggesting that Java is slow!

--
Lew

Lew, May 8, 2009
14. ### Joshua CranmerGuest

Thomas Pornin wrote:
> It shall be noted that on some architectures, including x86 CPU in
> 32-bit mode, floating-point computations are performed with an
> internal 80-bit format(**), regardless of whether operands were
> initially floats or doubles.

Doesn't strictfp require limiting the computation to be purely 32- or
64-bit?
"Within an FP-strict expression, all intermediate values must be
elements of the float value set or the double value set" (JLS 3 §15.4)

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

Joshua Cranmer, May 8, 2009

Lew wrote:

> One uses double when high precision is required, which is most of the
> time. One uses float when high precision is not so necessary, as,
> say, Swing does in calculating screen positions, and when speed is
> more important than precision.
>

Or if memory requirements dictate that the overhead of 64bit rather than 32bit
data is significant. For most programming applications these days this won't be
an issue. However, if you have to process very large arrays of real numbers it
could become significant, or are working on a system with very restricted
memory. There may also be cases where it's necessary/desirable to reduce
accuracy down to float before performing I/O over restricted bandwidth
transports, but still perform all the internal arithmetic as double.

The days when double was a luxury to be avoided unless essential have thankfully
passed. I don't see any reason not to use double as the default, and only use
float if necessary.

--

Christian wrote:

> Stefan Ram schrieb:
>> I teach some properties of the data type Â»doubleÂ«:
>>
>> public class Main
>> { public static void main( final java.lang.String[] args )
>> { java.lang.System.out.println( 0.1 + 0.1 + 0.1 == 0.3 );
>> java.lang.System.out.println( 1.1 * 1.1 == 1.21 ); }}
>>
>> false
>> false
>>
>> . I also teach that beginners should not use the data type
>> Â»floatÂ«, because it will only cause trouble.

>
> imho this is a bad thing to tell...
> Its like telling "Don't use int because it will only give you trouble
> , always use long"
>

This is a false comparison. Short, int and long all have identical accuracy, the
only difference is in their range. If the data you need to process can be held
in an int you might as well use an int, there is nothing whatever to be gained
by using long. This is most definitely not the case when dealing with floating
point numbers.

>
> For most applications (as in 99% of all I see) float is more than enough
> for floating point computations.

But why use float at all? Unless there is a compelling reason to do so (speed,
memory limitations) why not just use double as the default? There is no good
reason not to. Starting off by learning to use float gets you into the habit of
using float and may have serious repercussions at some later date.

> And as one usually uses int and it
> doesn't matter if you use long instead ... in some applications you are
> just better off with using int or short or byte where applicable ...
>
>
> There are 2 situations where double really starts to be useful ...
> 1. very high numbers ... and you don't want to use BigInt and co...

Or very small numbers

> 2. high numbers that need high precicision ... if the number is in the
> Billions and you still need precicion behind the comma ...

any number that requires higher precision, it's not a function of the magnitude
unless it exceeds the exponent limits of float.

>
> 2. sometimes happens i.e. if very large numbers are multiplied with very
> small ones.. like a * a^-1
> 1. is rather rare...

or when calculating the difference between a large and small number etc.

In fact, you might as well just use double everywhere, and only use float when
it's required...

--

17. ### Mark ThorntonGuest

Lew wrote:
> Mark Thornton wrote:
>> Nevertheless, it can be important to check our assumptions. Long ago I
>> did check for atomic assignment found that it didn't work. Just a few
>> days ago I found some code that depended on the behaviour of
>> Timestamp.getTime() as exhibited by JVMs up to 1.4. In 1.4, Sun
>> changed the behaviour and left the documentation very confusing
>> (especially for those aware of the previous behaviour).

>
> All right, I'll bite. What was the previous behavior, and how did it
> change in Java 1.4?
>
>> In this case I was just adding an historical note that there was some
>> basis for believing the assignments not to be atomic, but today it is
>> about as valid as suggesting that Java is slow!

>

Prior to 1.4 Timestamp.getTime() always returned a multiple of 1000;
that is an exact second. The fraction was then obtained from the
getNanoseconds method. From 1.4 the getTime() method returns
nanoseconds/1000000. The value returned by getNanoseconds hasn't
changed, so code that relied on the pre 1.4 behaviour tends to get an
overall time where the fractional seconds are counted twice.

I suspect this change resulted from an effort to reduce the problems
arising from mixing java.util.Date with java.sql.Timestamp (notably
comparisons didn't work properly).

Mark Thornton

Mark Thornton, May 8, 2009
18. ### LewGuest

On May 8, 4:14 pm, Mark Thornton <> wrote:
> Lew wrote:
> > Mark Thornton wrote:
> >> Nevertheless, it can be important to check our assumptions. Long ago I
> >> did check for atomic assignment found that it didn't work. Just a few
> >> days ago I found some code that depended on the behaviour of
> >> Timestamp.getTime() as exhibited by JVMs up to 1.4. In 1.4, Sun
> >> changed the behaviour and left the documentation very confusing
> >> (especially for those aware of the previous behaviour).

>
> > All right, I'll bite.  What was the previous behavior, and how did it
> > change in Java 1.4?

>
> >> In this case I was just adding an historical note that there was some
> >> basis for believing the assignments not to be atomic, but today it is
> >> about as valid as suggesting that Java is slow!

>
> Prior to 1.4 Timestamp.getTime() always returned a multiple of 1000;
> that is an exact second. The fraction was then obtained from the
> getNanoseconds method. From 1.4 the getTime() method returns
> nanoseconds/1000000. The value returned by getNanoseconds hasn't
> changed, so code that relied on the pre 1.4 behaviour tends to get an
> overall time where the fractional seconds are counted twice.
>
> I suspect this change resulted from an effort to reduce the problems
> arising from mixing java.util.Date with java.sql.Timestamp (notably
> comparisons didn't work properly).

Looking at the Javadocs for the Java 6 version of java.sql.Timestamp
<http://java.sun.com/javase/6/docs/api/java/sql/Timestamp.html>
I see:
> Note: This type is a composite of a java.util.Date and a separate nanoseconds value.
> Only integral seconds are stored in the java.util.Date component.

Since the change you describe for java.sql.Timestamp is a change in
specification, then my earlier arguments against reliance on bugs do
not apply to this case. Relying on an obsolete specification is not a
programmer's right. It's like relying on pre-Java 5 code that has a
variable or method named 'enum' and being angry that it violates Java
5's rules.

Apache commons-lang relied on a class-initialization bug that violated
the JLS extant at the time they relied on it, and when the bug was
fixed, Apache refused to correct their mistake. That's a horse of a
different color.

Also, since this is an API class, not part of the Java language
itself, and not mentioned in the JLS, my arguments about reliance on
the JLS don't apply to this case. Javadocs are generated from the
implementation of an API, and therefore are the product of an
interpretation of the specification for that API, not the
specification itself. There can be, and clearly sometimes are, errors
in the implementation of Javadocs just as in the Java source itself.

I am claiming that Java programmers have a right to rely on the JLS
for the version of Java we're using. The JLS is the rigorous,
normative description of Java's rules. I am also claiming that
violating those rules just because a bug happens to let you do so is

--
Lew

Lew, May 8, 2009
19. ### Roedy GreenGuest

On 7 May 2009 16:15:41 GMT, -berlin.de (Stefan Ram) wrote,
quoted or indirectly quoted someone who said :

>{ public static void main( final java.lang.String[] args )
> { java.lang.System.out.println( 0.1f + 0.1f + 0.1f == 0.3f );
> java.lang.System.out.println( 1.1f * 1.1f == 1.21f ); }}

Floats are for measuring desk sizes. It does not matter if the desk
is 143.99998 cm or 143.0 cm or 143.0002. You can't tell such desks
apart for any practical purpose. If you start treating floats like
currency you are in trouble. They are not SUPPOSED to add up to the
penny, just get the approximate answer over a wide range of
magnitudes.

See http://mindprod.com/jgloss/floatingpoint.html

Perhaps an analogy fretting over the inability of floats to add up
perfectly would be like judging Britney Spears for ability to do
carpentry. That is not what she is for. It is utterly preposterous to
hire her to remodel your bathroom, so judging her on that ability
makes no sense.

--
http://mindprod.com

"Species evolve exactly as if they were adapting as best they could to a changing world, and not at all as if they were moving toward a set goal."
~ George Gaylord Simpson

Roedy Green, May 9, 2009
20. ### Tom AndersonGuest

On Thu, 7 May 2009, Patricia Shanahan wrote:

> Tom Anderson wrote:
>> On Thu, 7 May 2009, Stefan Ram wrote:
>>
>>> . I also teach that beginners should not use the data type
>>> ?float?, because it will only cause trouble.

>>
>> Interesting. FWIW, i use doubles when i'm doing mathematics, and floats
>> when i'm doing sums - which is an aphoristic way of saying that i use
>> doubles when i'm doing calculations where i care about accuracy, range,
>> etc, whcih is things like numerical work, data processing, whatever, and
>> floats when i'm doing things like calculating a load factor for a
>> hashtable, or the index of the 95th centile in an array, etc.

>
> What is the advantage of float for the cases where you do use it?

Performance, of course!

There's no great advantage. For me, this works as a form of documentation
- whenever i see a float, i know it's something sums-ish rather than
mathematical.

tom

--
drink beer and forget about gods. -- derslangerman

Tom Anderson, May 9, 2009