Floating Point Bug in Visual Studio 2003

A

Anton Noll

We are using Visual Studio 2003.NET (C++) for the development
of our software in the fields digital signal processing and
numerical acoustics.

One of our programs was working correctly if we are using the
Debug-Version of the program, but it fails (or leads to false
results) if we are using the Release-Version. After a long
debugging session we found out, that our program was working
correctly, but the floating point processing (accuracy) of the
Debug-Version and the Release-Version is different and leads to
different numerical results.

This bug occurs independend of the optimization level which is
used for the Release-Version (even if optimization is disabled).

We have dedected this bug only in the C++ compiler of Visual
Studio 2003.NET. With Visual Studio 6 both versions of our
program are working (with the same results).

I have included a test program in this mail. If the program
below is compiled with Visual Studio 2003.NET the output of
the Debug- and the Release-Version is differnt.

Note: There is also a problem with casting floats to int. This
means, in some cases the result of "(int)x" in the Debug- and
the Release-Vesion is not the same.

I have tried to report this bug/problem to the microsoft company,
but after visiting a lot of web-pages without any chance to send
a note to microsoft i gave up.


Anton Noll
Austrian Academy of Sciences, Acoustics Research Institut
1010 Vienna, Reichsratstrasse 17, Austria
E-Mail: (e-mail address removed)


Test program (a part of a fir filter development algorithm)

----- BEGIN OF NUMTEST.CPP -----
// numtest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>

static float _dfunci0(float x)
{
float sa, uh, u=1, s=1;
int i = 1;
while(true)
{
sa = s;
uh = x / 2 / (float)i++;
u = u * uh * uh;
s = s + u;
if(sa == s) return s;
}
}

int _tmain(int argc, _TCHAR* argv[])
{
float delta = (float)1e-6, freq = (float)1;
float fe = (float)0.05, fg = (float)0.1;

int k, n;
float pi, a, df, fs, alpha, wn, hilf;
float *cw, *w,*c;

pi = (float)atan2((float)0,(float)-1);
a = (float)(-20 * log10(delta));
df = (fg-fe) / freq;
fs = (fg+fe) / 2 / freq;
n = int((a - 7.95) / 28.72 / df) + 1;

cw = new float[n+1];
c = new float[n+1];
w = new float[n+1];

if(a > 50)
alpha = (float)(0.1102 * (a-8.7));
else if(a > 21)
alpha = (float)(pow(0.5842*(a-21),0.4) + 0.07886*(a-21));
else
alpha = 0;

c[0] = 2*fs;
for(k = 1;k <= n; k++)
c[k] = sin(2 * pi * k * fs) / (pi * k);

wn = _dfunci0(alpha);
for(k = 0;k <= n; k++)
{
hilf = (float)1 - (float)(k*k) / (float)(n*n);
if(hilf <= 0)
hilf = 0;
else
hilf = alpha * sqrt(hilf);
w[k] = _dfunci0(hilf) / wn;
}

for(k = 0; k <= n; k++)
cw[k] = (float)(c[k] * w[k]);

FILE *test = fopen("numtest.txt","wt");
for(k = 0; k <= n; k++)
fprintf(test,"%g,%g,%g\n", c[k], w[k], cw[k]);
fclose(test);

return 0;
}
----- END OF NUMTEST.CPP -----
 
J

Jack Klein

We are using Visual Studio 2003.NET (C++) for the development
of our software in the fields digital signal processing and
numerical acoustics.

One of our programs was working correctly if we are using the
Debug-Version of the program, but it fails (or leads to false
results) if we are using the Release-Version. After a long
debugging session we found out, that our program was working
correctly, but the floating point processing (accuracy) of the
Debug-Version and the Release-Version is different and leads to
different numerical results.

If you are concerned with accuracy, why the heck are you using the
type float, which by its very nature has a limited accuracy?

And for that matter, why are you using any version of Visual C++? Use
a compiler that provides the full hardware precision of the FPU for
long double, instead of throwing it away for marketing reasons? Try
using gcc for Windows (the cygwin port, not mingw). Or Borland, or
any other compiler that does not throw away 16 bits of precision.

And looking through your code sample, I see a large number of
constants scattered through it, a very bad coding practice. These
should be defined as const values with meaningful names. But the most
important thing is that none of them has more than four significant
digits, even though the limited format you are using provides for six
significant decimal digits. Why not improve the accuracy of your
calculations by improving the accuracy of your constants?

On the other hand, why not just build your programs in debug mode, if
it gives you the result you want and you don't want to use a better
compiler for numerics, or even the most accurate floating point type
that your compiler provides?

Do you understand the limitations and compromises of floating point
arithmetic, especially using the very low precision Intel single
precision type? See this standard reference on the subject:

http://docs.sun.com/db/doc/800-7895/6hos0aou4
This bug occurs independend of the optimization level which is
used for the Release-Version (even if optimization is disabled).

The question I have is, what do you expect anyone in this group to do
for you? We can't fix Microsoft's compiler, if indeed it is broken.
Is there anything you expect to read here that can be of any use to
you other than telling you to use double for more precision or switch
to a different compiler?

The actual cause of the difference you see is most likely a difference
in the way some intermediate values are handled. Most likely in the
release version, more intermediate values are kept in FPU registers as
64-bit doubles instead of being truncated to 32 bits and stored to
memory.
We have dedected this bug only in the C++ compiler of Visual

What proof do you have that this is a bug?
Studio 2003.NET. With Visual Studio 6 both versions of our
program are working (with the same results).

I have included a test program in this mail. If the program
below is compiled with Visual Studio 2003.NET the output of
the Debug- and the Release-Version is differnt.

Note: There is also a problem with casting floats to int. This
means, in some cases the result of "(int)x" in the Debug- and
the Release-Vesion is not the same.

Do you understand these two things:

1. Casting a floating point value to int is not necessary and a
completely useless waste of typing? Assigning a floating point value
to an int does the conversion automatically, no cast required. If the
integral part of the float value is outside the range of int, you get
the same undefined behavior whether you use the cast or not?

2. Assignment of a floating point value to an integer type, with or
without a cast, is a truncating operation. It does not round. So if
you have a value that after having passed through several operations
is equal to 2.999999999, it will convert to the integer value 2, but
if you have 3.000000001, it will convert to the integer value 3?
I have tried to report this bug/problem to the microsoft company,
but after visiting a lot of web-pages without any chance to send
a note to microsoft i gave up.

Try asking in one of Microsoft's support groups in the
family, on the server msnews.microsoft.com.
Someone there can tell you how to file a report with Microsoft.
Anton Noll
Austrian Academy of Sciences, Acoustics Research Institut
1010 Vienna, Reichsratstrasse 17, Austria
E-Mail: (e-mail address removed)


Test program (a part of a fir filter development algorithm)

----- BEGIN OF NUMTEST.CPP -----
// numtest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>

static float _dfunci0(float x)
{
float sa, uh, u=1, s=1;

From a C++ point of view, or in fact from just about any programming
language, this program is terrible. Variable names like 'sa', 'uh',
'u', and 's' are inexcusable. Are you aware that using more
characters in the names of the variables does not make the program
larger or slower, and does not change the output?
int i = 1;
while(true)
{
sa = s;
uh = x / 2 / (float)i++;
u = u * uh * uh;
s = s + u;
if(sa == s) return s;

Please read a decent reference on floating point math in computer
programs. Especially what it has to say on comparing floating point
values for exact equality. For some values of 'x', this function will
never return.
}
}

int _tmain(int argc, _TCHAR* argv[])
{
float delta = (float)1e-6, freq = (float)1;
float fe = (float)0.05, fg = (float)0.1;

Are you aware that numbers like 0.05 and 0.1 cannot be represented
exactly in binary floating point representation?
int k, n;
float pi, a, df, fs, alpha, wn, hilf;
float *cw, *w,*c;

pi = (float)atan2((float)0,(float)-1);
a = (float)(-20 * log10(delta));
df = (fg-fe) / freq;
fs = (fg+fe) / 2 / freq;
n = int((a - 7.95) / 28.72 / df) + 1;

cw = new float[n+1];
c = new float[n+1];
w = new float[n+1];

if(a > 50)
alpha = (float)(0.1102 * (a-8.7));
else if(a > 21)
alpha = (float)(pow(0.5842*(a-21),0.4) + 0.07886*(a-21));
else
alpha = 0;

c[0] = 2*fs;
for(k = 1;k <= n; k++)
c[k] = sin(2 * pi * k * fs) / (pi * k);

wn = _dfunci0(alpha);
for(k = 0;k <= n; k++)
{
hilf = (float)1 - (float)(k*k) / (float)(n*n);
if(hilf <= 0)
hilf = 0;
else
hilf = alpha * sqrt(hilf);
w[k] = _dfunci0(hilf) / wn;
}

for(k = 0; k <= n; k++)
cw[k] = (float)(c[k] * w[k]);

FILE *test = fopen("numtest.txt","wt");
for(k = 0; k <= n; k++)
fprintf(test,"%g,%g,%g\n", c[k], w[k], cw[k]);
fclose(test);

return 0;
}
----- END OF NUMTEST.CPP -----
 
A

Alf P. Steinbach

* Jack Klein:
Try asking in one of Microsoft's support groups in the
family, on the server msnews.microsoft.com.
Someone there can tell you how to file a report with Microsoft.

Alas, although I agree with your other comments & advice, the problem
of reporting a "problem" (in MS speak even an Internal Compiler Error is at
worst a "problem") to Microsoft is a real one and of general interest even
in this group, because it's so widely used a compiler, and it's not solved
by posting to a Microsoft public or internal group.

Currently it's possible to report bugs in the Visual C++ 8.0 compiler, and
that was a great improvement on earlier (marketing-driven) practice.

Microsoft have had and probably still has reporting pages for earlier
versions, but these pages have, AFAIK, _never actually worked_; they have
just been very misleading, dishonest window dressing, a marketing effort.
For Visual C++ prior to version 8.0, there are AFAIK only three ways to
report a bug, such as an ICE: (1) be an MVP (Most Valued Professional),
which essentially means top-posting inane answers to inane questions in the
Microsoft group for a period of months or years until MVP-ship is endowed,
however that works, (2) work in firm with an established professional
relationship to Microsoft, or (3) shelve out some good money for no return.
 
G

Gianni Mariani

Anton Noll wrote:
....
We have dedected this bug only in the C++ compiler of Visual
Studio 2003.NET. With Visual Studio 6 both versions of our
program are working (with the same results).

It's more than likely not a "bug" as such with the compiler. This kind
of thing happens with floating point code. Floating point arithmetic
has many many issues with "non exactness".

See

http://support.microsoft.com/kb/q42980/

You could try using "double" instead of "float". double has 48 mantissa
bits on most architectures and "float" only has 24 (on most modern
machines). If this does not work, you will need to deal with issues
relating to round-off errors.

....
// numtest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
stdafx.h is not a standard C++ header - nuke this - you're not using it.

....
int _tmain(int argc, _TCHAR* argv[])

int main( int, char ** )
{
float delta = (float)1e-6, freq = (float)1;
float fe = (float)0.05, fg = (float)0.1;

Have you thought of using this code structure ?

float delta = 1e-6f;
float freq = 1.0f;
float fe = 0.05f;
float fg = 0.1f;

Much easier to read :0)
int k, n;
float pi, a, df, fs, alpha, wn, hilf;
float *cw, *w,*c;

A more acceptible C++ style is defining and initializing. This looks
like C style code (no need to do this in C++).
pi = (float)atan2((float)0,(float)-1);

Why all the conversions from int to float (and then a hidden conversion
to double) ?

float pi = atan2( 0, -1 );

So much easier to read....

a = (float)(-20 * log10(delta));
df = (fg-fe) / freq;
fs = (fg+fe) / 2 / freq;

Huge potential source of errors here if fg and fe are "close".
n = int((a - 7.95) / 28.72 / df) + 1;

cw = new float[n+1];
c = new float[n+1];
w = new float[n+1];

use std::vector ... much nicer.
....

You could also use a template for your code so you can switch it from
float to double (or even long double on some compilers) and check how
this behaves with your code changes.
 
V

velthuijsen

You could try using "double" instead of "float". double has 48 mantissa
bits on most architectures and "float" only has 24 (on most modern
machines). If this does not work, you will need to deal with issues
relating to round-off errors.

Where people follow the IEEE 754 (floating points) standard a float has
a 23 bits mantissa and a double has a 52 bits mantissa.
Due to a layout trick this is improved to 24 for float and 53 for
double (for people wondering how/why
http://stevehollasch.com/cgindex/coding/ieeefloat.html)
 
J

John Carson

Anton Noll said:
We are using Visual Studio 2003.NET (C++) for the development
of our software in the fields digital signal processing and
numerical acoustics.

One of our programs was working correctly if we are using the
Debug-Version of the program, but it fails (or leads to false
results) if we are using the Release-Version. After a long
debugging session we found out, that our program was working
correctly, but the floating point processing (accuracy) of the
Debug-Version and the Release-Version is different and leads to
different numerical results.

This bug occurs independend of the optimization level which is
used for the Release-Version (even if optimization is disabled).

We have dedected this bug only in the C++ compiler of Visual
Studio 2003.NET. With Visual Studio 6 both versions of our
program are working (with the same results).

I have included a test program in this mail. If the program
below is compiled with Visual Studio 2003.NET the output of
the Debug- and the Release-Version is differnt.

Note: There is also a problem with casting floats to int. This
means, in some cases the result of "(int)x" in the Debug- and
the Release-Vesion is not the same.

I have tried to report this bug/problem to the microsoft company,
but after visiting a lot of web-pages without any chance to send
a note to microsoft i gave up.


For what it is worth, I believe that if you choose the /Op compiler option
for both Debug and Release --- set in the IDE under

C/C++->Optimization->Floating-Point Consistency

--- then you will get the same results under Debug and Release. Reading the
documentation on this switch will provide further information.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top