Re: 0.0 versus 0.0f

From: Joseph M. Newcomer (newcomer_at_flounder.com)
Date: 10/20/04


Date: Wed, 20 Oct 2004 12:02:13 -0400

You said it treats it as a float rather than an int. But the specifc example he gave was

>float a = 0.5 + 0.7;
>
>versus
>
>float a = 0.5f + 0.7f;

which clearly has nothing to do with an int.
 
You said
>It tells the system to treat the value as a float rather than an int.
>In your example it does not matter really because the numbers are floats by
>definition. But in some cases it does.

0.5 is not a "float by definition" but a "double by definition", so it really does make a
difference. In particular, some compilers might issue a warning that a double value was
truncated to a float value. For example, the Microsoft C compiler does not complain about

float a = 10.0 / 20.0;

but complains about truncation when you write something that would lose significance,
e.g.,

float a = 10.0 / 3.0;

warning C4035: 'initializing' : truncation from 'const double' to 'float'

Your assertion also suggests that if integers were involved, he could write

float a = 10f / 20f;

but that is syntactically illegal C; the compiler throws up when seeing this ("C2059:
Syntax error 'bad suffix on number'") so your allegation that it distinguishes floats from
ints is erroneous. If that were its purpose, then the above line should compile.

But

 float a = 10.0 / 20.0;

is optimized at compile time so that it is as if the user coded

float a = 0.5;

And

float a = 10 / 20;

is optimized at compile time so that it is as if the user coded

float a = 0.0;

This is because the C language states, explicitly, that "When integers are divided and the
division is inexact, if both operands are positive the result of the / operator is the
largest integer less than the algebraic quotient...if either operand is negative, whether
the result of the / operator is the largest integer less than or equal to the algebraic
quotient or the smallest integer greater than or equal to the algebraic quotient is
implementation-defined, as is the sign of the result of the operator" (§6.3.5). Since both
operands are positive integers, the result is 0. By the rules of arithmetic conversions
(§6.2.1.5) this 0 is converted to 0.0. This is not an optimization. This is the semantics
of C. There is absolutely no question about "optimization" here.

Suppose I did

int result div(int a, int b)
    {
      return a/b;
    }

and called it as

float x = div(10, 20);

then optimization cannot be involved at all, and the result is STILL 0.0f. This is not
optimization, this is (a) how the C language defines it to work and (b) how the integer
divide operator in the hardware works. I See No Optimization Issue Here.

Your assertion that it distinguished a float from an int is wrong. It distiguishes a float
from a double.

Now suppose I rewriter your statement

>The exact reason goes all the way down to the way the numbers are
>represented in binary, telling the processor to forcefully make it into a
>float will make the equation different and include [carries].

Carries have little to do with the computation. Roundoff, scaling, and precision are
managed by the floating point unit, but carries have nothing to do with the problem at
all. Carries deal with simple bit addition, e.g., 1+1 = 0 with a carry of 1, and that is
true for all binary arithmetic, integer or floating point. The f suffix tells the compiler
(not the processor) to use a single-precision floating-point representaiton; otherwise a
double-precision floating point representation is assumed. The arithmetic instructions
generated in such a case, whether performed at compile time or run time, would be doing
either a single-precision floating point divide or a double-precision floating point
divide. The suffix f certainly makes the equation different, telling the compiler to
generate or use either single precision or double precision floating point arithmetic,
instead of integer arithmetic.

>As everything in C it depends on the math processor.

No, virtually nothing in C depends on the math processor, and the only thing that actually
depends on the math processor, at least as far as floating point, is the degree of
precision, 32-bit or 64-bit floating point, issues about overflow and underflow and the
effect of doing a divide by zero (generates, if I recall, a Not A Number value, but I
haven't worried about such fine points in floating point in over a decade), but this
hardly constitutes "everything in C" and the real definition is that the set of values of
float is a subset of the set of values of double, and the set of values of double isa
subset of the set of values of long double, and that is ALL the standard says about the
values (§6.1.2.5). The x86 implements IEEE standard floating point, so the hardware has
no latitude on what it is going to do; it must conform to the IEEE specification.

>The OP asked for a difference between the two and I gave it.

No, you didn't. You gave the wrong answer. You said it distinguished floats from ints. It
does not. It distinguishes floats from doubles.

>The reason i said it was simply to touch on why (int)10/(int)20 will return
>0 and needs to be defined as 10/20.f

But you said it was optimization; it isn't. The formula you give is the same as 10.f/20.f
(and it is the point, not the f, that makes the difference!) and is the same as 10/20.0;
the difference is that 10/20.f returns a float, while 10/20. returns a double, and
important distinction.
        float f = 10/3.f;
works but
        float f = 10/3.;
generates an error about loss of precision in truncating a double to a float.
                                joe

On Wed, 20 Oct 2004 02:06:39 +0100, "Florent" <spambucket@myoddweb.com> wrote:

>"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
>news:rjabn05jovnmh2rahjm4pc7oqrnfca7g7e@4ax.com...
>> Actually, it says it is a float rather than a DOUBLE, not an "int". A
>> float is a
>> single-precision floating-point number, on an x86 this is 32 bits.
>> Otherwise, it is a
>> double, a 64-bit floating point value.
>
>Sorry I am missing something here, where did I say a DOUBLE, (in upper or
>lower case)?
>And I did use the "int" correctly. I was trying to explain in simple terms
>that if the numbers are treated as "int" then there might be a problem.
>I am not sure what DOUBLE vs. float has to do with what I said.
>
>>
>> 10/20 is not "optimized as an integer"; optimization has little to do with
>> this.
>
>Yes it is optimised. That's why you forcefully need to tell the compiler
>when it is a float, a long or what ever.
>
>> The computation specified is an integer divide of 10 by 20, and whether it
>> is done a compile
>> time or run time, an integer divide of 10 by 20 always gives 0.
>
>Is it not what I said? 10/20 is treated as Integers and that is why it will
>return 0.
>had you said 10/20.f the application would have treaded the equation has
>floats. hence the reason for the "f".
>
>The OP asked for a difference between the two and I gave it.
>
>>
>> I'm not sure what a "math processor" is; all x86 chips since the 486 have
>> built-in
>> floating point operations, so an external floating-point math coprocessor
>> no longer exists
>> as a concept. And C has NEVER had a dependence of the presence or absence
>> of a math
>> coprocessor; the language defines what is supposed to happen, and whether
>> that occurs in
>> hardware or software doesn't matter.
>
>Yes, you are right it is a math co-processor sorry for the typo. But I
>suspect you knew all along what I meant.
>"Built in floating point operations" sounds a lot like co-processor to me, I
>never said it was internal or external but thanks for pointing that valuable
>piece of information out.
>And the language does define what happens, but how is the language supposed
>to know what you were trying to do? maybe by using things like "f".
>That is precisely <sic> why I said, if you do "10/20" but in fact wanted
>"10/20.f" then you need to tell the program what you wish to do.
>
>>
>> And what is a "carriage"?
>
>Sorry my english failled me here. I was talking about binary equations when
>you carry over.
>The reason i said it was simply to touch on why (int)10/(int)20 will return
>0 and needs to be defined as 10/20.f
>
>Something like, http://mathforum.org/library/drmath/view/55951.html
>
>> joe
>>
>
>Florent

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm



Relevant Pages

  • Re: cpu type idea
    ... compiler related recently. ... int main ... float a; ... just to parallelize the vectror and tensor operations. ...
    (alt.lang.asm)
  • Re: getting avg of long and std::vector::size_type
    ... the compiler starts by evaluating a/b. ... int and b is an int, so it performs integer division on a and b. ... Now the compiler starts with the cast. ... first step is to convert a to a float. ...
    (comp.lang.cpp)
  • Re: Good C Question | pointer problem
    ... int main{ ... This allocates an array of 100 chars and putting the result in ptr. ... This will give you 100/sizeof (float) entries. ... You did not store any floating point values at fpor fp ...
    (comp.programming)
  • Re: static_cast<unsigned int> question...
    ... > unsigned int test2; ... This is caused by the way the float type store number internally. ... floating point value to: ... This is also the reason why comparing two floating point values with the ...
    (comp.lang.cpp)
  • Re: matrix stuff (solving b = A*x) --> using numerical recipes
    ... Numerical recipes (can be seen on ... Ok, I added it now (actually I also had it at some earlier moment, but then I removed it since I couldn't see any compiler warnings/errors without stdio.h). ... void banmul(float **a, unsigned long n, int left, int right, float x, float b); ...
    (comp.lang.c)