1

My software has to show end result to a user, the data is received though UART port, then I need to format and round the data.

I did write algorihtm to do that, but my feeling is that there has to be a better solution.

My output can have mutiple ranges, that i need to round and format correctly.

Example:

1 of many results go from ->

0.000 Ohm to 2.000 Ohm

2.01 Ohm to 20.00 Ohm

20.1 Ohm to 100.0 Ohm

100 Ohm to 200 Ohm

I made a simple structure to hold basic data for formating

struct _range
{
  float from; //0.000 for first example 
  float to; //2.000 
  int decimal; //3, decimal places I need
  int unit; //Unit to format, Ohm in my example
  float div; //sometimes I need to divide the result at some range
  //example, when I reach 1000VA I need to divide by 1000 to get 1kVA
};

I have a static function called AddUnitToResult, this one will add unit to my result.

Now I am asking you to help me write a function that will correctly format the result to string and round it to double ( I need double for later to compare it ).

Correctly format means that even if result is 0, it should format it to 3 dedimal places.

I hope you can help me guys

Edit:

This is what I currently have to handle round and dividing.

void ResultBox::SetResult(float res)
{
    this->measureCounter++;
    this->valueAVG +=res;
    if (res > this->valueMax)
        this->valueMax = res;
    if (res < this->valueMin)
        this->valueMin = res;


    float tttmp;
    if (this->RangeCount > 0 && this->ranges[0].decimal >= 0)
    {
        tttmp = Converter::cutDecimal(res,this->ranges[0].decimal);
    }




    int decimal = GetDecimalPlaces(res,0);

    float div = GetDivision(res);

    int unit = GetUnit(res);
    tttmp=tttmp/div;
    this->result = tttmp;

    float tmpRes = res /div; 
    this->isValid =true;

    WCHAR resText[20];
    WCHAR finalText[20];
    WCHAR maxText[20];
    WCHAR minText[20];

    char resTEXT[20];

    tmpRes = res/div;;

    std::ostringstream ss;
    ss << std::fixed << std::setprecision(decimal) << tttmp;
    std::string s = ss.str();
    if (decimal > 0 && s[s.find_last_not_of('0')] == '.')
    {

        s.erase(s.size()-decimal+1);
    }



    Converter::dtoa(resTEXT,tmpRes);
    switch(decimal)
    {
    case 0:
        if (floor(tttmp) == tttmp)
        {
            swprintf(resText,L"%.0f",tttmp);
        }else
        {
            swprintf(resText,L"%S",s.c_str());
        }

        swprintf(maxText,L"%.0f",this->GetMax());
        swprintf(minText,L"%.0f",this->GetMin());
        break;
    case 1:
        if (floor(tttmp) == tttmp)
        {
            swprintf(resText,L"%.1f",tttmp);
        }else
        {
            swprintf(resText,L"%S",s.c_str());
        }

        swprintf(maxText,L"%.1f",this->GetMax());
        swprintf(minText,L"%.1f",this->GetMin());
        break;
    case 2:
        if (floor(tttmp) == tttmp)
        {
            swprintf(resText,L"%.2f",tttmp);
        }else
        {
            swprintf(resText,L"%S",s.c_str());
        }

        swprintf(maxText,L"%.2f",this->GetMax());
        swprintf(minText,L"%.2f",this->GetMin());
        break;
    case 3:
        if (floor(tttmp) == tttmp)
        {
            swprintf(resText,L"%.3f",tttmp);
        }else
        {
            swprintf(resText,L"%S",s.c_str());
        }

        swprintf(maxText,L"%.3f",this->GetMax());
        swprintf(minText,L"%.3f",this->GetMin());
        break;
    case 4:
        if (floor(tttmp) == tttmp)
        {
            swprintf(resText,L"%.4f",tttmp);
        }else
        {
            swprintf(resText,L"%S",s.c_str());
        }

        swprintf(maxText,L"%.4f",this->GetMax());
        swprintf(minText,L"%.4f",this->GetMin());
        break;
    case 5:
        if (floor(tttmp) == tttmp)
        {
            swprintf(resText,L"%.5f",tttmp);
        }else
        {
            swprintf(resText,L"%S",s.c_str());
        }

        swprintf(maxText,L"%.5f",this->GetMax());
        swprintf(minText,L"%.5f",this->GetMin());
        break;
    }


    //pogledamo če je majni
    if (res < this->GetMin())
    {
        if (LowerEnabled == true)
        {
            wcscpy(finalText,L"<");
        }
        else
        {
            wcscpy(finalText,L"");
        }
        wcscat(finalText,minText);
    }
    else if (res > this->GetMax())
    {
        wcscpy(finalText,L">");
        wcscat(finalText,maxText);
    }
    else
    {
        wcscpy(finalText,resText);
    }
    if (res == this->GetMin())
    {
        wcscpy(finalText,minText);
    }
    if (res == this->GetMax())
    {
        wcscpy(finalText,maxText);
    }

    if (this->unitBox)
    {
        WCHAR mm[10];
        wcscpy(mm,L"");
        TABSGuiProxy::MargeResultAndUnit(mm,unit);
        if (mm[0] == ' ')
            this->unitBox->SetText(&mm[1]);
        else
            this->unitBox->SetText(mm);
    }

    this->m_ptextBlock->SetText(finalText);
    if (this->resultLimit)
    {
        if (unit == MEASRUEMENT_UNITS::kVA)
        {
            float fff = this->resultLimit->GetValue()*1000;
            std::wostringstream ss1;
            ss1 << std::fixed << std::setprecision(decimal) << fff;
            std::wstring s1 = ss1.str();
            if (decimal > 0 && s1[s1.find_last_not_of('0')] == '.')
            {
                s1.erase(s1.size()-decimal+1);
            }

            if (wcscmp(resText,s1.c_str()) == 0)
            {

                this->SetGoodResult();
            }else
            {
                float mmm = fabs(_wtof(s1.c_str()) - this->resultLimit->GetValue()*1000) ;
                //else if (fabs(IDelResoult - IDeltaLim) <= 0.001 || IDelResoult < IDeltaLim)
                if (mmm<= 0.001 || tttmp < (_wtof(s1.c_str())))
                {
                    this->SetGoodResult();
                }
                else
                {
                    this->SetBadResult();
                }
            }
        }
        else
        {
            float fff = this->resultLimit->GetValue();
            std::wostringstream ss1;
            ss1 << std::fixed << std::setprecision(decimal) << fff;
            std::wstring s1 = ss1.str();
            if (decimal > 0 && s1[s1.find_last_not_of('0')] == '.')
            {
                s1.erase(s1.size()-decimal+1);
            }

            if (wcscmp(resText,s1.c_str()) == 0)
            {

                this->SetGoodResult();
            }
            else
            {
                float mmm = fabs(_wtof(resText) - this->resultLimit->GetValue()) ;
                //else if (fabs(IDelResoult - IDeltaLim) <= 0.001 || IDelResoult < IDeltaLim)
                if (mmm<= 0.001 || tttmp < (_wtof(s1.c_str())))
                {
                    this->SetGoodResult();
                }
                else
                {
                    this->SetBadResult();
                }
            }
        }
    }

}

Let me try to explain a bit more:

I use struct _range to set valid ranges for my output, when I init result I create mutiple struct of type range.

Let say I have:

Range1 -> 0.000 to 2.000 Ohm Range2 -> 2.01 to 20.00 Ohm Range3 -> 20.1 to 100.0 Ohm Range4 -> 101 to 200 Ohm

When I init my result I create an array of 4 struct each containing this data

Range1 -> 
struct _range
{
  float from    = 0.000 
  float to      = 2.000
  int   decimal =3;
  int   unit        = Ohm; //Unit to format, Ohm in my example
  float div     =1; 
};

Range2 -> 
struct _range
{
  float from    = 2.01 
  float to      = 20.00
  int   decimal =2;
  int   unit        = Ohm; //Unit to format, Ohm in my example
  float div     =1; 
};

Range3 -> 
struct _range
{
  float from    = 20.1 
  float to      = 100.0
  int   decimal =1;
  int   unit        = Ohm; //Unit to format, Ohm in my example
  float div     =1; 
};

Range4 -> 
struct _range
{
  float from    = 101 
  float to      = 200
  int   decimal =0;
  int   unit        = Ohm; //Unit to format, Ohm in my example
  float div     =1; 
};

Now Input to my function can be from 0 to 200, and I have to format text and round the float acording to ranges in the structures.

I hope this explains it a bit more

Cœur
  • 37,241
  • 25
  • 195
  • 267
Luka Pivk
  • 466
  • 2
  • 19
  • It's really rather tough to figure out what your question is, as you've got rounding, numeric ranges, and comparisons all tied together. I believe one of the things you're trying to solve is to ensure that numbers have trailing zeros; a solution to that is here: http://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf – Ross Jul 23 '13 at 14:42
  • Hi, my Eng is not the best, so I have hard time explaining what I want, I actualy want to get formated text and rounded float, out of function, considering all parameters in struct. Currently my code is a mess and has to many excptions in my opinion, thats why I am asking for help – Luka Pivk Jul 23 '13 at 14:46
  • I do not find your English to be a problem, and I'm certain your English is better than my Slovenian. The difficulty is that it is difficult to understand the scope of your problem. I can't figure out what "from" "to" and "div" represent within the rounding function. Are values supposed to be clipped to be within the "from" "to" range? Or if you get out of range then you "div" it? Again, the overall objective isn't clear. – Ross Jul 23 '13 at 15:02
  • I added some explanation, I hope it helps – Luka Pivk Jul 23 '13 at 15:09

4 Answers4

1

I think you could start to improve this code by adding a "format" member to your _range struct like this:

struct _range
{
  float from; //0.000 for first example 
  float to; //2.000 
  int decimal; //3, decimal places I need
  int unit; //Unit to format, Ohm in my example
  float div; //sometimes I need to divide the result at some range
  //example, when I reach 1000VA I need to divide by 1000 to get 1kVA
  char * format;
};

Then initialize the instances of the range struct like this:

Range1.from    = 0.000;
Range1.to      = 2.000;
Range1.decimal = 3;
Range1.format  = "%.3f";

Range2.from    = 2.01;
Range2.to      = 20.00;
Range2.decimal = 2;
Range2.format  = "%.2f";

Then reference the format string for the appropriate range instance when you print the value. Maybe like this:

sprintf(pstr, pRangeOfValue->format, value);
kkrambo
  • 6,643
  • 1
  • 17
  • 30
0

You can use the following function in std before you std::cout:

std::setprecision(5)

This will allow the number to be rounded to 5 decimal places for example.

Joseph Pla
  • 1,600
  • 1
  • 10
  • 21
0

Simply - use sprintf. Example:

float variable = 0.0f;
const char buffer[ 7 ];
sprintf( buffer, "3.3f", variable ); 
// 3.3f => 3 places before dot and 3 after
// Examples:
//   0.123
//  12.200
// 123.456
Radosław Miernik
  • 4,004
  • 8
  • 33
  • 36
  • This works Ok untll you say that variable is 2.2968 and want to print to 3 decimals without extra rounding sprintf does. – Luka Pivk Jul 23 '13 at 08:22
0
printf("3.3f",variable);

should do the trick in displaying up to 3 decimal places.

ctrl-shift-esc
  • 876
  • 1
  • 9
  • 19
  • printf, does extra rounding that I dont want. Try inputing 2.2968; That is mostly why I have problems – Luka Pivk Jul 23 '13 at 08:23
  • 2
    @LukaPivk: What do you mean by "extra rounding". It rounds conventionally toward zero if the next digit is <5 otherwise it rounds away from zero. What kind of rounding do you need? We could try 2.2968, but it is not clear what you expect. I would expect 2.297 - what did you want? – Clifford Jul 23 '13 at 15:04