Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

CVF 6.6C Numerics

Nick2
New Contributor I
832 Views
A certain app compiled with CVF 6.6C, on a given line, has an equation like this:

MWSUB = AFLCOR*XWSUB/VWSUB

Depending on whether or not I instruct my app to change the value of AFLCOR from 8.862 to 8.862, I get two different sets of values for the above variables at run-time:

first set -

MWSUB 5998.806
AFLCOR 8.862000
XWSUB 0.9020565
VWSUB 1.3326025E-03

second set -

MWSUB 5998.807
AFLCOR 8.862000
XWSUB 0.9020565
VWSUB 1.3326025E-03

I don't recall whether I tried the same with IVF. The question here is simply, WTF? Thanks in advance for any words of wisdom. My flags follow. I am running WinXP-SP2, 32-bit.

# ADD BASE F90 /check:bounds /compile_only /debug:full /include:"Debug/" /nologo /warn:argument_checking /warn:nofileopt
# ADD F90 /automatic /check:bounds /check:overflow /compile_only /debug:full /fpe:0 /include:"Debug/" /nologo /recursive /traceback /warn:argument_checking
# SUBTRACT F90 /warn:nofileopt
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib /nologo /subsystem:console /debug /machine:I386 /out:"BWR4DOS.exe" /pdbtype:sept

0 Kudos
9 Replies
cfrieler
Beginner
833 Views
A more complete code sample would make this more certain, but.....

I believe if you change the print format to binary, you'll see that one of the arguments has changed value. Going through a print statement may actually change the representation as well, so this is not a complete test.

A more complete answer:
The first thing to remember is that the fundamental representation is binary, not decimal. this means that any time you print something in decimal, you are likely seeing and approximation of the variables true value.
The second is that an x86 processor has a certain binary representation when the variables are in registers, and the length while in register differs from the representation they have when they are moved out to RAM or written to disk. I used to know the exact lengths, back in the i486 era, but I'm sure there are web resources where you can get current details.
The fallout from both of these is that numbers can slightly change if you do anything in the code that forces a variable to move from register to memory, disk or display.
Note that there is a compiler switch to force consistent precision on all variables.

If you want an official and very detailed description of this problem and what the Intel compilers allow you to do about it, search for
347684.pdf
on this web site.

Regards, Cliff

0 Kudos
Nick2
New Contributor I
832 Views
Great info! I'm not sure if the 80-bit representation in registers vs. 32-bit representation in my (single-precision) variables plays a role. (Unfortunately, this is not the first time I have this kind of a problem.) Having looked through the code paths, both the first and the second time I do the variable change, I end up through the same algorithm: convert the string to a real, assign the real to the common block variable.

Is there an easy way to look at the binary representation of a variable inside the debugger? The values I printed are copy-pasted from the debugger's watch window.

I use no optimizations. I tried "enable floating point consistency."

What mildly surprised me is that IVF 10.0.25 and G95 don't have this problem. Is CVF getting that old?
0 Kudos
jimdempseyatthecove
Honored Contributor III
832 Views

If you are using VS, right click on the value of the variable being viewed and click on Hex format. Repeat to turn back to decimal format.

Jim Dempsey

0 Kudos
TimP
Honored Contributor III
832 Views
In order to conform to Microsoft ABI, CVF and IVF 32-bit initialize x87 precision mode to 53-bit. Thus, when you don't set SSE options, all expressions are promoted to double precision evaluation in register. The difference between 64-bit and 80-bit storage is suppressed, except for extended exponent range and differences in underflow behavior, as long as you didn't set 64-bit precision in your code. The Fortran library string conversions may use the 64-bit precision internally; if so, they restore the precision mode (normally, 53-bit) which was set upon entry to those library functions. When you store data to a default real in COMMON, they are rounded down. There is little possibility of predicting where the extra precision effects will come in over a large body of code, and where they differ among compilers. That is one place where a "problem," as you put it, may occur. When you don't set /fltconsistency, shortcuts are taken which may depend on the extra precision to give reasonably correct results, and may skip over operations which would round down to single precision. If extra precision is a "problem" for your application, you should be careful that it doesn't fail for other unavoidable precision related issues.
0 Kudos
Nick2
New Contributor I
833 Views
Tim,

It sounds like this is a current area of active research; am I correct? I noticed that IVF didn't give me these kinds of problems, CVF did even with /fltconsistency, and LF 95 was significantly worse than CVF 6.6. The obvious difference between the three is their release dates. Can I expect the same, or even more improvements, in numerical consistency with 64-bit Windows/IVF?
0 Kudos
TimP
Honored Contributor III
832 Views
Normally, with ifort, you would set an SSE option, so you would not see the extra precision effects of CVF. 64-bit ifort doesn't even have an x87 option. 64-bit ifort 10 has /QxW as the default.
/fltconsistency (or /Op) prevents some aggressive optimizations which can hurt accuracy, but does not avoid inconsistent extra precision effects. In fact, it may introduce more of them, when used with SSE. In the 64-bit ifort, this promotion of expressions to double costs more performance loss. So, it has evolved into an option to be used where best results depend on extra precision.
The most recent (not) LF95 I own, like CVF, doesn't have an SSE option. There was an option somewhat like /fltconsistency.
Improvements made in recent ifort (when SSE options are in force) include replacing the old /fltconsistency options with /fp:precise (9.1 and 10) and, in 10.0, introducing /assume:protect_parens, so you can get full optimization without violating parentheses.
/fp:precise includes the options /assume:protect_parens /Qprec-div /Qprec-sqrt /Qftz- , thus avoiding the optimizations which are most risky, along with disabling some additional optimizations which may affect numerical results.
In 10.1, I hope to see correction of some problems with -O3, but otherwise not much change from 10.0.
0 Kudos
Nick2
New Contributor I
833 Views
Amazingly, I managed to pin-point this to a single routine/line of code.

We start out with a string that has a value of either '8.86200' or '8.862'. Read in the integer part, save the number 8. Read in the decimal part, save it as either 862 or 86200. Do a lil math, and we end up with a real number, value 8.862000, something like this:

RNUM= ISSUM*( JSUM+JDSUM/(10.E0**IDIV) )*(10.E0**JEXP)

(ISSUM is 1, JEXP is 0, all the variables are integers).

Here's the kicker: if the string value is '8.862000', the hex value is #410DCAC1. If the string value is '8.862', the hex value is #410DCAC0. If I evaluate the expression in the Watch window, either way I get #410DCAC0.

I'm convinced to write this off to (ancient) compiler/platform issues.
0 Kudos
g_f_thomas
Beginner
833 Views

If you search on the Technology & Research link above you'll find an interesting paper (I can't remember the author's name) dealing witharithmetical issues on Itanium processors and how its math lib will provide results good to the last ulp with other Intel commodity processors.

Gerry

0 Kudos
jimdempseyatthecove
Honored Contributor III
833 Views

If you want consistent results then consider stripping off trailing 0's in the fraction part of the input string.

Jim Dempsey

0 Kudos
Reply