We help IT Professionals succeed at work.

Need some help to C++ if statement to catch the -0.01 to -0.99

Thomas Stockbruegger
Thomas Stockbruegger used Ask the Experts™
on
Need some help to C++ if Statement.
I will not catch the -0.01 to -0.99 with this if statement.
The crText will be blue and not red
prozent= double variable
                  
                   if(prozent<0)
                   {
                          crText = RGB(255,0,0);      //red
                     }
                   else
                   {
                         crText = RGB(0,0,255);      //blue
                     }
Please let me know how I can fix this simple statement.
Thank you.
Best regards,
Thomas
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Senior Developer
Commented:
Without the entire method, it can be anything. Cause the if() itself handles "all values" of your variable prozent.

So either this if() is not reached or your variable contains a different value than expected. So debug it or add some logging..
Bill PrewTest your restores, not your backups...
Top Expert 2016
Commented:
Your code looks okay, at least what we can see of it.  In a simople test here, this produced "RED" as expected...

    double prozent = -.01;
                  
    if(prozent<0)
    {
        //crText = RGB(255,0,0);      //red
        cout<<"RED";
    }
    else
    {
        //crText = RGB(0,0,255);      //blue
        cout<<"BLUE";
    }

Open in new window


»bp
void CStatistik_UMA::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
 {
	 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );

    // Take the default processing unless we set this to something else below.
    *pResult = 0;

    // First thing - check the draw stage. If it's the control's prepaint
    // stage, then tell Windows we want messages for every item.

    if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
        {
        *pResult = CDRF_NOTIFYITEMDRAW;
        }
    else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
        {
        // This is the notification message for an item.  We'll request
        // notifications before each subitem's prepaint stage.

        *pResult = CDRF_NOTIFYSUBITEMDRAW;
        }
    else if ( (CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage )
        {
        // This is the prepaint stage for a subitem. Here's where we set the
        // item's text and background colors. Our return value will tell 
        // Windows to draw the subitem itself, but it will use the new colors
        // we set here.
        
    
            COLORREF crText, crBkgnd;

			//------------------verschiedene Reihen in Farbe ----------------------
			//MemberVariable m_bAnzeige_Typen = true ->Typen Auswahl    false->alle anderen
			int iCol = pLVCD->iSubItem;
			int iRow = pLVCD->nmcd.dwItemSpec;

			CString str_help=m_List.GetItemText(iRow,14);//Reihe 14 und 17 grauer Balken
			
			//-------------------------------------------------------------------------------
	   		if(m_bAnzeige_Typen==false && m_bAnzeige_KundenUmsatz==false)//also nicht bei Typen
			{
                if(pLVCD->nmcd.dwItemSpec==14 ||pLVCD->nmcd.dwItemSpec==17)
			    {
				
		          crBkgnd = RGB(192,192,192);     //grau
			    }
			    else
		     	{
				
		          crBkgnd = RGB(255,255,224); //beige
			    }
			}
           //---------------------------------------------------------------------------

			
			 
			//-------------------------------------------------------------------------------
            if(m_bAnzeige_Typen==false && m_bAnzeige_KundenUmsatz==true)//KundenUmsatz
			{
				CString str_help=m_List.GetItemText(iRow,0);
				if(str_help=="Ges.")
				{
					 crText = RGB(0,0,255);   //blau  
   				     crBkgnd = RGB(0,191,255);//hellblau  
				}
				else if(str_help=="Ges.:")//Gesamt Total am Ende
				{
					  crText = RGB(0,0,255);      //blau
					  crBkgnd = RGB(255,255,0);   //gelb
				}
				else  
				{
					  crText = RGB(0,0,255);      //blau
					  crBkgnd = RGB(255,255,224); //beige
				}

			}
           		
			//-------------------------------------------------------------------------------
			if(m_bAnzeige_Typen==true)// Typen
			{
				int fabwechsel = pLVCD->iSubItem;
				if(fabwechsel %2!=0)//alle Columns die durch 2 teilbar sind (module Operator)
				{
					 crBkgnd = RGB(255,255,224);     //beige
			    }
			    else
		     	{
				
		          crBkgnd = RGB(255,255,255); //weiß
				  
				}
				if(pLVCD->iSubItem==0)//erste Spalte auch in beige
				{
					crBkgnd = RGB(255,255,224);     //beige
				}


                if(pLVCD->nmcd.dwItemSpec==m_Anzahl_der_Typen+2||pLVCD->nmcd.dwItemSpec==m_Anzahl_der_Typen)
			    {
				
		          crBkgnd = RGB(192,192,192);     //grau Balken
			    }
			  
			}

         [b]   //--------------------- negative Zahlen in rot -----------------------------
			 str_help=m_List.GetItemText(iRow,iCol);
			 double prozent;
			 prozent=atof(str_help);

			
			 if(prozent<0)
			 {
				  crText = RGB(255,0,0);      //rot
		  	 }
			 else
			 {
				 crText = RGB(0,0,255);      //blau
	      	 }[/b]
		     //--------------------------- High / Low Werte in Farbe ----------------------
			 // MemberVariablen
			 // m_highWert_Zeile   m_highWert_Spalte
		    //  m_lowWert_Zeile    m_lowWert_Spalte
			if(m_highWert_Spalte!=99999999 && 	m_lowWert_Spalte!=99999999)
			{

			    if(m_bAnzeige_KundenUmsatz ==false)
			    {
                     if(pLVCD->nmcd.dwItemSpec==m_highWert_Zeile && pLVCD->iSubItem==m_highWert_Spalte)
			         {
                          crBkgnd = RGB(191,239,255);     // HighWert blau
			         }
			
			         if(pLVCD->nmcd.dwItemSpec==m_lowWert_Zeile && pLVCD->iSubItem==m_lowWert_Spalte)
			         { 
                          crBkgnd =RGB(255,193,193);     // LowWert rot RGB(255,64,64);     // LowWert rot
			        }
			    }
			}
			//-------------------------------------------------------------------------------
			 if(m_bAnzeige_Typen==true)// Typen  Graue Zahlen bei % Anteil
			{
				int fabwechsel = pLVCD->iSubItem;
				if(fabwechsel>0 && fabwechsel %2==0)//alle Columns die durch 2 teilbar sind (module Operator)
				{
					 crText = RGB(105,105,105);     //dunkel grau
			    }
			}
            //-------------------------------------------------------------------------------
			UpdateData(TRUE);
			bool bTypen= m_checkbox_Typen.GetCheck();
			if(m_SteuerungTypen==1)
			{
                if(4==pLVCD->iSubItem)//Typenspalte andere Farbe
				{
					crText = RGB(0,205,102);       
					 
				}
			}

                 
	    // Store the colors back in the NMLVCUSTOMDRAW struct.
        pLVCD->clrText = crText;
        pLVCD->clrTextBk = crBkgnd;

        // Tell Windows to paint the control itself.
        *pResult = CDRF_DODEFAULT;
        }
}
 //-------------------------------------------------------------------------------

Open in new window


The code is in OnCustomdrawList.
Top Expert 2016
Commented:
I  will not catch the -0.01 to -0.99 with this if statement.


double prozent = -0.990000001;   // double prozent = -0.009999999);
bool bneg = (prozent < 0.);

if (bneg && (int)((prozent+0.000000001)*100) >= -99 && (int)((prozent-0.000000001)*100) <= -1) 
{
       crText = RGB(0,0,255);      //blue
}
else
{ 
       crText = RGB(255,0,0);      //red
}

Open in new window


something like that?  

the if condition is falsefor prozent in the range of -0.990000001  to -0.009999999

be adding or subtracting a (very) small value we would correct rounding errors which are unavoidable because a double internally won't exactly match a decimal (mostly).

Sara
Thank you Sara for your answer.
The code will not work.... with your code every prozent, the text is in blue.
Print the value of the string str_help before the if statement.
 For the range you give from  -0.01 to -0.99, you do not have to worry about roundoff errors . Those are concerns for an equality test for values near 0 (in this case), not inequality test for the small negative value of -0.01.
I found the solution....very simple it was my mistake (today is Monday)
                         str_help=m_List.GetItemText(iRow,iCol);
                   double prozent;
                   str_help.Replace(',',',.');
                   prozent=atof(str_help);



In my List View the data is in German writing : with a "," f.e.  0,33  -0,33
I have to replace the "," with "." then it works
Sorry to bother you.
Best regards,
Thomas
Thank you for your time
ste5anSenior Developer

Commented:
hmm, I thought atof() uses the locales correctly, doesn't it?
Top Expert 2016
Commented:
atof() uses the locales correctly
strtod would use the locales but not (depricated) atof.

The code will not work.
yes, i made a mistake after i recognized that you do NOT want the percent values within the range to get red.

correct code:

double epsilon = 0.000000001;
if ((prozent+epsilon) < -0.99 || (prozent-epsilon) > -0.01)
{
        color = RGB(255, 0, 0);
}
else
{
       color = RGB(0, 0, 255);
}

Open in new window


the epsilon correction is necessary if the prozent was calculated and the result could be very near to -0.01 or -0.99. a double has a precision of about 9 significant digits. if you use decimal double constants like -0.01, the value is not exactly -0.01 but -0.010000000... or -0.0099999999 normally continuing with an infinite series of arbitrary digits. same applies for calculated results. that way a condition like (prozent < -0.01) could be true even if both sides would print as -0,01. and (prozent == -0,01) is false for almost all cases if one or both values are the result of a calculation rather than of an assignment of a literal.

str_help.Replace(',',',.');

a way out of the precision issue with double is to use strings which have an exact decimal presentation. however, it is rather expensive (and laborious) to format the string such you can do a string comparison.


#include <string>
#include <sstream>
#include <iomanip>
//...

COLORREF GetColor(double prozent)
{  
    COLORREF color = RGB(0, 0, 0);
    std::ostringstream oss;
    // this will convert (and round) the prozent to positive string number with 8 decimal places.
    if (oss << std::right << std::setw(10) << std::setfill('0') << std::fixed << std::setprecision(8) << -prozent)
    {
             std::string strprozent = oss.str();
             bool bred = (prozent < 0.) && !(strprozent >= "0.01000000" && strprozent <= "0.99000000");
             color = bred? RGB(255,0,0) : RGB(0,0,255);
    }
    return color;
}

int main()
{
    double prozent1  = -0.0099999;   // red
    double prozent2  = -0.9900001;   // red
    double prozent3  = -0.0299;      // blue
    double prozent4  = -0.5001;      // blue

    COLORREF col1 = GetColor(prozent1);
    COLORREF col2 = GetColor(prozent2);
    COLORREF col3 = GetColor(prozent3);
    COLORREF col4 = GetColor(prozent4);
    return 0;
}


note, converting the string back to double doesn't help, because you may have the same (odd) rounding experiences at both ends of the range as before.

anyway, if you want to convert string numbers use the strtod and not atof.

Sara
Thank you Sara for the explanation in detail !