Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

## _Quad + __powq strange behaviour

Beginner
263 Views

Hello,

I will be brief. This code:

_Quad x = 1.0 / __powq(0.0001, 2);

double y = x;

givesy a value of 99999999.999999985, while this:

_Quad x = 1.0 / __powq(0.0001q, 2);

double y = x;

(the only difference being the q in the literal) gives the correct, 100000000.00000000, result. Casting 0.0001 to _Quad in the first example doesn't work either. If I use pow (that is, Microsoft's overload, accepting double), instead of __powq, in the first example, it seems to work properly. It is strange also, because:

double foobar = foo; // this seems to give a correct result

_Quad x = 1.0 / foo;

double y = x; // not any more

The prototype I am using is:

This is happening on a Windows XP machine, using Visual Studio 2008 SP1 with Intel's C++ Compiler version 11.1.054.

Any insight into what might be happening, why, and how do I fix it? The problem, obviously, is that I don't have a literal there.

3 Replies
Black Belt
263 Views
0.0001 is a double constant. Even if cast afterwards to a wider type, it still retains the value rounded to nearest representable double.
I won't try to guess exactly what you want to fix (your own code, or the decisions Microsoft made about supporting only double, or something else).
Beginner
263 Views
Yes, 0.0001 IS a double constant. But I can't explain why this works:

double x = 1.0 / pow(0.0001, 2.0);

And this does not:

double y = 1.0 / __powq(0.0001, 2.0);

It seems that double is "precise enough" for this computation to work, because the first example is fine. I would imagine that the problem is in the casting process - 0.0001 double is somehow "wrongly" converted to a not-0.0001 quad.

Anyway, so my question is this: I have a text file which in it has the number 0.0001. I want to read that number into a _Quad, then compute 1.0 / __powq(number, 2) and then write the result back to another text file. Can you explain how do I do that?
Black Belt
263 Views
As the docs tell you, there is no support in Microsoft rtl for extended or quad precision scanf/printf, and icl adds none. If you wanted to read 0.0001 as 0.00010000000000000000000000000000000, you would have to write in some work-around of your own. For example, you could multiply by 10000 and round to nearest integer (double will work, if you don't overflow; maybe libimf will support rint(), or you can easily write one), then multiply by 0.0001q. This would "clean up" your inputs up to 4 digits after decimal point. You could write your own atoq() if you chose (assuming you don't find one readily available); I would expect it to be quite slow.
You're not going to convince anyone that 0.0001 is "wrongly converted to quad" when you have
( (0.0001 == _Quad(0.0001) ) == 1
You can't expect the compiler to read your mind, or use context look ahead to say "Oh, he's going to use the double as a quad later on; we should replace the double by quad from the beginning." That contextual data typing battle was fought and resolved in Fortran back when C had nothing but double. C still doesn't have _Quad or anything bigger than long double, whose interpretation is left up to the implementor. Switch to linux if you want standardization of long double.
When you use the supplied sprintf(), evidently, your outputs are rounded to double before converting to string; that looks OK, to the extent you have divulged your requirements.