Incorrect floating point behavior - c++

When I run the below C++ program in a 32-bit powerpc kernel which supports software floating emulation (hardware floating point disabled), I get a incorrect conditional evaluation. Can some tell me what's the potential problem here?
#include <stdio.h>
int main() {
int newmax = 1;
if ((newmax + 0.0) > 256) {
printf("\nShouldn't be here\n");
} else {
printf("\nShould be here\n");
}
}
Compile:
powerpc-linux-g++ -msoft-float -c floating.cxx
powerpc-linux-g++ -o floating floating.o
Output in target system:
[linux:/]$ ./floating
Shouldn't be here

You should specify -msoft-float also when linking
Give us a dissassembly with the -S flag: powerpc-linux-g++ -msoft-float -c floating.cxx -S -o floating.s

First, why hardware floating point is disabled?
Because of this type casts may be performed in incorrect order.
(double)1 = 0x3FF0000000000000
(float) 1 = 0x3F800000
This is your condition.
if ((newmax + 0.0) > 256)
In your case:
1) newmax casting to float or double;
2) adding 0.0;
3) gotten value casting back to int.
It depends on your machine, but int usually is 32-bit value. To check it you can use:
int i;
printf("%d", sizeof(i));
Anyway, going back to your problem, after calculated value converting into int you get big positive number. In your situation I would print it/or compare not with 0x100 but with
0x3F800000,
0x3FF0000000000000,
0x3FF00000
To find out, what happened, but disassembling is the best option.
Probably it wasn't so helpfull, but that was just my idea, what happened.

This could be anything from compiler error to assembler error to linker error to kernel error. As other people already pointed out: Compiler errors - which is the most likely source of this error - could be verified (or ruled out), if you provided the output of compiling with the -S option. If it is not a compiler error, a kernel error with the floating point emulation would be the next likely source of the problem.

The statement in your code newmax + 0.0 produces a result in float or double but is compared with an integer value.
thus this error.
Try this out,
int i=1;
printf("%d",(i+0.0));
you get a result 0 everytime no matter what the value of i.
Whereas,
int i=1;
printf("%f",(i+0.0));
This produces 1.0000

Related

avr-gdb: No symbol "x" in current context

I'm debugging this function compiled with -g -ggdb -gstabs -Og on an AVR 8-bit controller:
usbMsgLen_t usbFunctionSetup(uchar data[8]) {
usbRequest_t *req = (void *)data;
if (req->bRequest == CUSTOM_REQ_TMP) {
// temperature in °C multiplied by 10
int16_t tmpx10 = (mVAvgTmp >> EWMA_BS) - 500;
// relative humidity in % multiplied by 10
uint32_t rhx10 = (mvAvgRh * 100 - (75750 << EWMA_BS)) / (318 << EWMA_BS);
static char msg[16];
snprintf(msg, sizeof(msg), "%d|%ld", tmpx10, rhx10);
usbMsgPtr = (usbMsgPtr_t)msg;
asm("break");
return sizeof(msg);
}
// return no data for unimplemented requests
return 0;
}
When execution stops at the manually inserted break instruction, avr-gdb prints the value of msg with the correct values of tmpx10 and rhx10:
(gdb) p msg
$1 = "200|528\000\000\000\000\000\000\000\000"
but for tmpx10 it prints a wrong value and for rhx10, it says No symbol "rhx10" in current context.:
(gdb) p tmpx10
$2 = 116
(gdb) p rhx10
No symbol "rhx10" in current context.
even though both variables are in the same scope as msg.
What am I missing?
-Og will perform minimal optimisation, but it's not no optimisation. At the point you are stopped both tmpx10 and rhx10 are no longer needed, so it is possible that their locations have been reused for something else (tmpx10) or maybe that the debug info doesn't even describe the location any more (rhx10).
You're right, that -Og should ensure this doesn't happen, and you might consider raising a compiler bug, but the reality is that, especially when there's optimisation in use, getting these cases right all the time is hard.
I'm also curious why you're using -gstabs. If you're compiler is GCC, and you're debugging with GDB, I'd have though using the default DWARF would give you better results.
Finally, when I compile for debugging, I use -g3 -O0 which include the maximum debug information and the least (no) optimisation. This might give you better results.

Bad optimization of std::fabs()?

Recently i was working with an application that had code similar to:
for (auto x = 0; x < width - 1 - left; ++x)
{
// store / reset points
temp = hPoint = 0;
for(int channel = 0; channel < audioData.size(); channel++)
{
if (peakmode) /* fir rms of window size */
{
for (int z = 0; z < sizeFactor; z++)
{
temp += audioData[channel][x * sizeFactor + z + offset];
}
hPoint += temp / sizeFactor;
}
else /* highest sample in window */
{
for (int z = 0; z < sizeFactor; z++)
{
temp = audioData[channel][x * sizeFactor + z + offset];
if (std::fabs(temp) > std::fabs(hPoint))
hPoint = temp;
}
}
.. some other code
}
... some more code
}
This is inside a graphical render loop, called some 50-100 times / sec with buffers up to 192kHz in multiple channels. So it's a lot of data running through the innermost loops, and profiling showed this was a hotspot.
It occurred to me that one could cast the float to an integer and erase the sign bit, and cast it back using only temporaries. It looked something like this:
if ((const float &&)(*((int *)&temp) & ~0x80000000) > (const float &&)(*((int *)&hPoint) & ~0x80000000))
hPoint = temp;
This gave a 12x reduction in render time, while still producing the same, valid output. Note that everything in the audiodata is sanitized beforehand to not include nans/infs/denormals, and only have a range of [-1, 1].
Are there any corner cases where this optimization will give wrong results - or, why is the standard library function not implemented like this? I presume it has to do with handling of non-normal values?
e: the layout of the floating point model is conforming to ieee, and sizeof(float) == sizeof(int) == 4
Well, you set the floating-point mode to IEEE conforming. Typically, with switches like --fast-math the compiler can ignore IEEE corner cases like NaN, INF and denormals. If the compiler also uses intrinsics, it can probably emit the same code.
BTW, if you're going to assume IEEE format, there's no need for the cast back to float prior to the comparison. The IEEE format is nifty: for all positive finite values, a<b if and only if reinterpret_cast<int_type>(a) < reinterpret_cast<int_type>(b)
It occurred to me that one could cast the float to an integer and erase the sign bit, and cast it back using only temporaries.
No, you can't, because this violates the strict aliasing rule.
Are there any corner cases where this optimization will give wrong results
Technically, this code results in undefined behavior, so it always gives wrong "results". Not in the sense that the result of the absolute value will always be unexpected or incorrect, but in the sense that you can't possibly reason about what a program does if it has undefined behavior.
or, why is the standard library function not implemented like this?
Your suspicion is justified, handling denormals and other exceptional values is tricky, the stdlib function also needs to take those into account, and the other reason is still the undefined behavior.
One (non-)solution if you care about performance:
Instead of casting and pointers, you can use a union. Unfortunately, that only works in C, not in C++, though. That won't result in UB, but it's still not portable (although it will likely work with most, if not all, platforms with IEEE-754).
union {
float f;
unsigned u;
} pun = { .f = -3.14 };
pun.u &= ~0x80000000;
printf("abs(-pi) = %f\n", pun.f);
But, granted, this may or may not be faster than calling fabs(). Only one thing is sure: it won't be always correct.
You would expect fabs() to be implemented in hardware. There was an 8087 instruction for it in 1980 after all. You're not going to beat the hardware.
How the standard library function implements it is .... implementation dependent. So you may find different implementation of the standard library with different performance.
I imagine that you could have problems in platforms where int is not 32 bits. You 'd better use int32_t (cstdint>)
For my knowledge, was std::abs previously inlined ? Or the optimisation you observed is mainly due to suppression of the function call ?
Some observations on how refactoring may improve performance:
as mentioned, x * sizeFactor + offset can be factored out of the inner loops
peakmode is actually a switch changing the function's behaviour - make two functions rather than test the switch mid-loop. This has 2 benefits:
easier to maintain
fewer local variables and code paths to get in the way of optimisation.
The division of temp by sizeFactor can be deferred until outside the channel loop in the peakmode version.
abs(hPoint) can be pre-computed whenever hPoint is updated
if audioData is a vector of vectors you may get some performance benefit by taking a reference to audioData[channel] at the start of the body of the channel loop, reducing the array indexing within the z loop down to one dimension.
finally, apply whatever specific optimisations for the calculation of fabs you deem fit. Anything you do here will hurt portability so it's a last resort.
In VS2008, using the following to track the absolute value of hpoint and hIsNeg to remember whether it is positive or negative is about twice as fast as using fabs():
int hIsNeg=0 ;
...
//Inside loop, replacing
// if (std::fabs(temp) > std::fabs(hPoint))
// hPoint = temp;
if( temp < 0 )
{
if( -temp > hpoint )
{
hpoint = -temp ;
hIsNeg = 1 ;
}
}
else
{
if( temp > hpoint )
{
hpoint = temp ;
hIsNeg = 0 ;
}
}
...
//After loop
if( hIsNeg )
hpoint = -hpoint ;

C++ and pin tool -- very weird DOUBLE variable issue with IF statement

I am working with pin tool that simulates a processor and having a very strange problem.
In the code snippet below, Router::Evaluate() is called repeatedly many times. After it is called several million times, strange behavior occurs intermittently where "_cycles != 0" is evaluated to be true in the first IF statement and to be false in the immediately following IF statement, falling into ELSE block.
void Router::Evaluate( )
{
//---------debug print code---------
if (_cycles != 0) {
cout << "not a zero" << endl;
if (_cycles != 0) cout << "---not a zero" << endl;
else cout << "---zero" << endl;
}
//----------------------------------
_cycles += _speedup;
while ( _cycles >= 1.0 ) {
_Step();
_cycles -= 1.0;
}
}
//class definition
class Router : public TimedModule {
Protected:
double _speedup; //initialized to 1.0
double _cycles; //initialized to 0.0
...
}
Below is the output of the code where "not a zero" followed by "---zero" is printed out from time to time seemingly randomly.
not a zero
---zero
(...some other output...)
not a zero
---zero
(...some other output...)
How could this possibly happen? This is not a multi-threaded program, so synchronization is not an issue. The program is compiled with gcc4.2.4 and executed on 32-bit CentOS. Does anybody have a clue?
Thanks.
--added---
I should have mentioned this, too. I did try printing the value of _cycles each time, and it is always 0.0, which should not be possible...
I also used the following g++ options: "-MM -MG -march=i686 -g -ggdb -g1 -finline-functions -O3 -fPIC"
Unless you have a horrible compiler bug, I would guess something like this is happening:
_cycles has some small fraction remaining after the subtractions. As long the compiler knows nothing else is changing its contents, it keeps its value in a higher precision floating point register. When it sees the I/O operation it is not certain the value of _cycles is needed elsewhere, so it makes sure to store its contents back to the double-precision memory location, rounding off the extra bits that were in the register. The next check assumes pessimistically the value might have changed during the I/O operation, and loads it back from memory, now without the extra bits that made it non-zero in the previous test.
As Daniel Fischer mentioned in a comment, using -ffloat-store inhibits the use of high-precision registers. If the problem goes away when using this option then the scenario I described is very likely. Check the assembly output of Router::Evaluate to be sure.

warning errors problem

Program:
void DibLaplacian8Direct(CDib sourceImg)
{
register int i,j;
int w = sourceImg.GetWidth();
int h = sourceImg.GetHeight();
CDib cpyImage = sourceImg;
BYTE** pSourceImg = sourceImg.GetPtr();
BYTE** pCpyImage = cpyImage.GetPtr();
float G;
for(j =1;j<h-1;j++)
{
for(i =1;i<w-1;i++)
{
G = -1*pCpyImage[j-1][i-1] + -1*pCpyImage[j-1][i] + (-1)*pCpyImage[j-1][i+1]+
(-1)*pCpyImage[j][i-1] + 8*pCpyImage[j][i] + (-1)*pCpyImage[j][i+1]+
-1*pCpyImage[j+1][i-1] + (-1)*pCpyImage[j+1][i] + -1*pCpyImage[j+1][i+1];
pSourceImg[j][i] = (BYTE)G;
}
}
}
warning error:
warning.. Can't coonvert from int to float..
Warning 1 warning C4819: The file contains a character that cannot be represented in the current code page (1257). Save the file in Unicode format to prevent data loss D:\2nd\imagetool\dibfilter.cpp 1 1 ImageTool
I do't understand that why its making me warning of int to float.
and for warning 1,
I am using VS 2010.. i do't know that i am getting warning in StdAfx.h include file .
Amy one can help me with this .
The first warning is due to the fact that a float has only six significant figures whereas an int can have more. If it does, then accuracy is lost.
In general, you cannot convert an integer to floating point without possible losing data. Also, you cannot convert from floating point back to integer without losing the deceimal places, so you get a warning again.
A simple minimalistic code example of the above case:
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=3;
float c;
c=a/b;
cout << c << endl;
return 0;
}
If you are sure of the data being in the range and there wont be any loss of accuracy you can use typecasting to get rid of the warning.
G = (float) (.....)
Check this for the second warning.
To get rid of the second warning you need to save the file in Unicode format.
Go to file->advanced save options and under that select the new encoding you want to save it as. UTF-8 or UNICODE codepage 1200 are the settings you want.
It is important to understand what the compiler is telling you with warning 20. The issue is that floating point numbers have only 23 bits of precision, while ints have 31. If your numbers is larger than 2^23, you will lose the low bits by storing in a float.
Now your number can never be larger than 2^23, so you are fine. Still, it is important to know what is going on here. There is a reason for that warning, and simply putting in the cast without understanding what is going on may mess you up some day.
In your specific case, I am not at all clear on why you are using a float. You are adding nine integers, none of which can be greater than 2^11. You have plenty of precision in an int to do that. Using a float is just going to slow your program down. (Probably quite a bit.)
Finally, that last cast to BYTE is worrisome. What happens if your value is out of range? Probably not what you want. For example if BYTE is unsigned, and your float ends up -3.0, you will be storing 253 as the result.

GCC problem with raw double type comparisons

I have the following bit of code, however when compiling it with GCC 4.4 with various optimization flags I get some unexpected results when its run.
#include <iostream>
int main()
{
const unsigned int cnt = 10;
double lst[cnt] = { 0.0 };
const double v[4] = { 131.313, 737.373, 979.797, 731.137 };
for(unsigned int i = 0; i < cnt; ++i) {
lst[i] = v[i % 4] * i;
}
for(unsigned int i = 0; i < cnt; ++i) {
double d = v[i % 4] * i;
if(lst[i] != d) {
std::cout << "error # : " << i << std::endl;
return 1;
}
}
return 0;
}
when compiled with: "g++ -pedantic -Wall -Werror -O1 -o test test.cpp" I get the following output: "error # : 3"
when compiled with: "g++ -pedantic -Wall -Werror -O2 -o test test.cpp" I get the following output: "error # : 3"
when compiled with: "g++ -pedantic -Wall -Werror -O3 -o test test.cpp" I get no errors
when compiled with: "g++ -pedantic -Wall -Werror -o test test.cpp" I get no errors
I do not believe this to be an issue related to rounding, or epsilon difference in the comparison. I've tried this with Intel v10 and MSVC 9.0 and they all seem to work as expected. I believe this should be nothing more than a bitwise compare.
If I replace the if-statement with the following: if (static_cast<long long int>(lst[i]) != static_cast<long long int>(d)), and add "-Wno-long-long" I get no errors in any of the optimization modes when run.
If I add std::cout << d << std::endl; before the "return 1", I get no errors in any of the optimization modes when run.
Is this a bug in my code, or is there something wrong with GCC and the way it handles the double type?
Note: I've just tried this with gcc versions 4.3 and 3.3, the error is not exhibited.
Resolution: Mike Dinsdale noted the following bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 It seems the GCC team are not completely sure about nature of problem.
As suggested in the bug report a possible resolution is to use the ffloat-store option. I've tried this and it works, however the results from a performance point of view are not that great, though ymmv.
The fact that the result depends on the optimization settings suggests it might be the x87 extended precision messing with things (as Michael Burr says).
Here's some code I use (with gcc on x86 processors) to switch the extended precision off:
static const unsigned int PRECISION_BIT_MASK = 0x300;
///< bitmask to mask out all non-precision bits in the fpu control word \cite{INTEL}.
static const unsigned int EXTENDED_PRECISION_BITS = 0x300;
///< add to the fpu control word (after zeroing precision bits) to turn on extended precision \cite{INTEL}.
static const unsigned int STANDARD_PRECISION_BITS = 0x200;
///< add to the fpu control word (after zeroing precision bits) to turn off extended precision \cite{INTEL}.
void set_fpu_control_word(unsigned int mode)
{
asm ("fldcw %0" : : "m" (*&mode));
}
unsigned int get_fpu_control_word()
{
volatile unsigned int mode = 0;
asm ("fstcw %0" : "=m" (*&mode));
return mode;
}
bool fpu_set_extended_precision_is_on(bool state)
{
unsigned int old_cw = get_fpu_control_word();
unsigned int masked = old_cw & ~PRECISION_BIT_MASK;
unsigned int new_cw;
if(state)
new_cw = masked + EXTENDED_PRECISION_BITS;
else
new_cw = masked + STANDARD_PRECISION_BITS;
set_fpu_control_word(new_cw);
return true;
}
bool fpu_get_extended_precision_is_on()
{
unsigned int old_cw = get_fpu_control_word();
return ((old_cw & PRECISION_BIT_MASK) == 0x300);
}
Or you can just run your code with valgrind, which doesn't simulate the 80-bit registers, and is probably easier for a short program like this!
The problem is likely the result of losing some precision when storing the result of an expression vs. the compiler not doing so in a local as an optimization:
double d = v[i % 4] * i; // the result, `d`, might be kept in a register
// instead of storing it in a memory location,
// keeping full precision
if(lst[i] != d) { // the value stored in lst[i] may have lost some
// precision since it had to be stored in memory,
// which might not be able to hold the full
// precision that the expression generated
The C99 standard says in 6.3.1.8/2 "Usual arithmetic conversions":
The values of floating operands and of the results of floating expressions may be
represented in greater precision and range than that required by the type; the types are not
changed thereby.
The width of the floating point registers in x86 is different from the width of the double in RAM. Therefore comparisons may succeed or fail depending entirely on how the compiler decides to optimize the loads of floating point values.