April 02, 2005
"Derek Parnell" <derek@psych.ward> wrote in message news:eouhnxxkjb80$.clvse1356mlr.dlg@40tude.net...
> There seems to be different treatment of literals and variables.

No, there isn't. The reason for the difference is when you assign the literal to z. Use the 'L' suffix for a real literal.





April 02, 2005
On Fri, 1 Apr 2005 18:50:40 -0800, Walter wrote:

> "Derek Parnell" <derek@psych.ward> wrote in message news:eouhnxxkjb80$.clvse1356mlr.dlg@40tude.net...
>> There seems to be different treatment of literals and variables.
> 
> No, there isn't. The reason for the difference is when you assign the literal to z. Use the 'L' suffix for a real literal.

Ok, I did that. And I still can't explain the output.

                                            Raw                    Floor
Using float  variable:         0x1.3fffff4afp+4                 0x1.3p+4
Using double variable:                 0x1.4p+4                 0x1.3p+4
Using real   variable:  0x1.4000000000000002p+4                 0x1.4p+4
Using float   literal:         0x1.3fffff4afp+4                 0x1.4p+4
Using double  literal:                 0x1.4p+4                 0x1.4p+4
Using real    literal:  0x1.4000000000000002p+4                 0x1.4p+4

Look at the results for doubles. How does floor(0x1.4p+4) give 0x1.3p+4 when the expression is a variable and give 0x1.4p+4 when the expression is a literal?

-- 
Derek Parnell
Melbourne, Australia
2/04/2005 3:34:22 PM
April 02, 2005
On Sat, 2 Apr 2005 15:39:01 +1000, Derek Parnell wrote:

I've reformatted the display to make it easier to spot the anomaly.

                                            Raw                    Floor
Using float  variable:         0x1.3fffff4afp+4                 0x1.3p+4
Using float   literal:         0x1.3fffff4afp+4                 0x1.4p+4

Using double variable:                 0x1.4p+4                 0x1.3p+4 Using double  literal:                 0x1.4p+4                 0x1.4p+4

Using real   variable:  0x1.4000000000000002p+4                 0x1.4p+4 Using real    literal:  0x1.4000000000000002p+4                 0x1.4p+4

And here is the program that created the above ...
<code>
import std.stdio;
import std.math;
import std.string;

void main() {

  float  x;
  double y;
  real   z;


  x = 0.0000195F;
  y = 0.0000195;
  z = 0.0000195L;
  writefln("                       %24s %24s","Raw","Floor");
  writefln("Using float  variable: %24a %24a",
                    (.5 + 1e6*x), floor(.5 + 1e6*x));
  writefln("Using float   literal: %24a %24a",
                    (.5 + 1e6*0.0000195f), floor(.5 + 1e6*0.0000195f));

  writefln("");
  writefln("Using double variable: %24a %24a",
                    (.5 + 1e6*y), floor(.5 + 1e6*y));
  writefln("Using double  literal: %24a %24a",
                    (.5 + 1e6*0.0000195), floor(.5 + 1e6*0.0000195));

  writefln("");
  writefln("Using real   variable: %24a %24a",
                    (.5 + 1e6*z), floor(.5 + 1e6*z));

  writefln("Using real    literal: %24a %24a",
                    (.5 + 1e6*0.0000195l), floor(.5 + 1e6*0.0000195l));


}
</code>
-- 
Derek Parnell
Melbourne, Australia
2/04/2005 4:48:12 PM
April 02, 2005
"Derek Parnell" <derek@psych.ward> wrote in message news:124cwpdauczht$.1wqi8sqkdi4ec.dlg@40tude.net...
> Ok, I did that. And I still can't explain the output.

Recall that, at runtime, the intermediate values are allowed to be carried out to 80 bits. So,

    floor(.5 + 1e6*y)

is evaluated as:

    floor(cast(real).5 + cast(real)(1e6) * cast(real)y);

whereas:

    floor(.5 + 1e6*0.0000195)

is evaluated as:

    float(cast(real)(.5 + 1e6*0.0000195))

hence the difference in result.


April 02, 2005
I have started a new thread: "80 Bit Challenge",
which should serve as a reply to your post ....



April 02, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:d2lodh$2qhf$1@digitaldaemon.com...
>
> "Derek Parnell" <derek@psych.ward> wrote in message news:124cwpdauczht$.1wqi8sqkdi4ec.dlg@40tude.net...
>> Ok, I did that. And I still can't explain the output.
>
> Recall that, at runtime, the intermediate values are allowed to be carried out to 80 bits. So,
>
>    floor(.5 + 1e6*y)
>
> is evaluated as:
>
>    floor(cast(real).5 + cast(real)(1e6) * cast(real)y);
>
> whereas:
>
>    floor(.5 + 1e6*0.0000195)
>
> is evaluated as:
>
>    float(cast(real)(.5 + 1e6*0.0000195))
>
> hence the difference in result.
>


It's C legacy hidden in the way the compiler parses
this code. You'll be facing these kind of questions
over and over again, unless you move a step further
away from C and let the compiler treat unsuffixed
literals as the "internal compiler floating point
precision format".

See my thread: "80 Bit Challenge"



April 02, 2005
On Sat, 2 Apr 2005 01:23:46 -0800, Walter wrote:

> "Derek Parnell" <derek@psych.ward> wrote in message news:124cwpdauczht$.1wqi8sqkdi4ec.dlg@40tude.net...
>> Ok, I did that. And I still can't explain the output.
> 
> Recall that, at runtime, the intermediate values are allowed to be carried out to 80 bits. So,
> 
>     floor(.5 + 1e6*y)
> 
> is evaluated as:
> 
>     floor(cast(real).5 + cast(real)(1e6) * cast(real)y);
> 
> whereas:
> 
>     floor(.5 + 1e6*0.0000195)
> 
> is evaluated as:
> 
>     float(cast(real)(.5 + 1e6*0.0000195))
> 
> hence the difference in result.

Got it.

So to summarize, in expressions that contain at least one double variable, each term is promoted to real before expression evaluation, but if the expression only contains double literals, then the terms are not promoted to real.

Why did you decide to have this anomaly?

-- 
Derek Parnell
Melbourne, Australia
2/04/2005 11:46:44 PM
April 02, 2005
"Derek Parnell" <derek@psych.ward> wrote in message news:lsphadeuh4s3.gjqbum65kx87$.dlg@40tude.net...
> So to summarize, in expressions that contain at least one double variable, each term is promoted to real before expression evaluation, but if the expression only contains double literals, then the terms are not promoted to real.
>
> Why did you decide to have this anomaly?

It's the way C works.


April 02, 2005
On Sat, 2 Apr 2005 10:04:32 -0800, Walter wrote:

> "Derek Parnell" <derek@psych.ward> wrote in message news:lsphadeuh4s3.gjqbum65kx87$.dlg@40tude.net...
>> So to summarize, in expressions that contain at least one double variable, each term is promoted to real before expression evaluation, but if the expression only contains double literals, then the terms are not promoted to real.
>>
>> Why did you decide to have this anomaly?
> 
> It's the way C works.

I understand. And here I was thinking that D was meant to be better than C. My bad.

-- 
Derek Parnell
Melbourne, Australia
3/04/2005 8:13:09 AM
April 03, 2005
"Derek Parnell" <derek@psych.ward> wrote in message news:lsphadeuh4s3.gjqbum65kx87$.dlg@40tude.net...
> On Sat, 2 Apr 2005 01:23:46 -0800, Walter wrote:
>
>> "Derek Parnell" <derek@psych.ward> wrote in message news:124cwpdauczht$.1wqi8sqkdi4ec.dlg@40tude.net...
>>> Ok, I did that. And I still can't explain the output.
>>
>> Recall that, at runtime, the intermediate values are allowed to be
>> carried
>> out to 80 bits. So,
>>
>>     floor(.5 + 1e6*y)
>>
>> is evaluated as:
>>
>>     floor(cast(real).5 + cast(real)(1e6) * cast(real)y);
>>
>> whereas:
>>
>>     floor(.5 + 1e6*0.0000195)
>>
>> is evaluated as:
>>
>>     float(cast(real)(.5 + 1e6*0.0000195))
>>
>> hence the difference in result.
>
> Got it.
>
> So to summarize, in expressions that contain at least one double variable, each term is promoted to real before expression evaluation, but if the expression only contains double literals, then the terms are not promoted to real.
>
> Why did you decide to have this anomaly?
>
> -- 
> Derek Parnell
> Melbourne, Australia
> 2/04/2005 11:46:44 PM


Some further info:

Currently it seems that in the D language no
literal is ever promoted to real directly if it
was not suffixed with a "L". You can cast(real)
it, and it will still be a double which is
converted to a crippled real in the FPU, because
some of its matissa bits went missing.

There are many exceptions though: All floating
point integers (1.0 2.0 10.0 etc.) and fractions
like 0.5 0.25 0.125 etc. are converted to proper
real values, because they are accurately
represented in binary floating point formats.
But even they are initially doubles, which are
just unharmed by the conversion because most
of their trailing mantissa bits are zero.

Any other fractional number (e.g. 1.2) cannot be
represented accurately in the binary system, so
its double representation is not equivalent to
its real representation (nor is it to the decimal
literal). If such a double is converted to real,
it is missing several bits of precision, so it
will not correspond accurately to its properly
converted counterpart (e.g. 1.2L).

As a summary: If you feel the need using
extended double (real) precision in D,
never ever forget the "L" for literals unless
you want "special effects".

Examples:

real r=1.2L;      // proper 80 bit real assigned to r
real r=1.2;       // inaccurate truncated 80 bit real
real r=2.4/2.0;   // inaccurate (2.4 loses precision)
real r=2.4/2.0L;  // inaccurate for the same reason
real r=2.4L/2.0;  // this one will work (2.0 == 2.0L)
real r=2.4L/2.0L; // thats the safe way to do it
real r=cast(real)1.2;  // inaccurate, converted from
                               // 1.2 as a double

By the way, C does it the same way for historic
reasons. Other languages are more user friendly
and I am still hoping that D might evolve in this
direction.