[haiku-development] Re: DeskCalc Improvements (was need strtold() function)

  • From: Stephan Assmus <superstippi@xxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Thu, 31 Dec 2009 10:01:31 +0100

Hi John,

On 2009-12-31 at 09:30:41 [+0100], John Scipione <jscipione@xxxxxxxxx> 
wrote:
> > I rewrote my DeskCalc changes so that I would not be doing any char* 
> > manipulation. To achieve this had to extend the ExpressionParser Class 
> > with two new methods: EvaluateToStandard() and EvaluateToScientific(). 
> > Each of these methods takes an int32 argument to specify the number of 
> > digits to grab. Trailing zeros after the decimal point are removed. 
> > Please review my patch below. Should patch from the haiku/ directory.
> >
> > Index: headers/private/shared/ExpressionParser.h
> > ===================================================================
> > --- headers/private/shared/ExpressionParser.h   (revision 34828)
> > +++ headers/private/shared/ExpressionParser.h   (working copy)
> > @@ -45,6 +45,11 @@
> >                        void                            
> >                        SetSupportHexInput(bool enabled);
> >
> >                        BString                         Evaluate(const 
> >                        char* expressionString);
> > +                       BString                         
> > EvaluateToStandard(
> > +                                    const char* expressionString,
> > +                                    int32 decimalPlaces);
> > +                       BString                         
> > EvaluateToScientific(const char*
> > +                                    expressionString, int32 
> > decimalPlaces);
> >                        int64                           
> >                        EvaluateToInt64(const char* expressionString); 
> >                        double                          
> >                        EvaluateToDouble(const char* expressionString);
> >
> > Index: src/apps/deskcalc/CalcView.cpp
> > ===================================================================
> > --- src/apps/deskcalc/CalcView.cpp      (revision 34828)
> > +++ src/apps/deskcalc/CalcView.cpp      (working copy)
> > @@ -894,6 +894,9 @@
> >  void
> >  CalcView::Evaluate()
> >  {
> > +    const double STD_NOTATION_UPPER = 1e16;
> > +    const double STD_NOTATION_LOWER = 1e-16;
> > +
> >        BString expression = fExpressionTextView->Text();
> >
> >        if (expression.Length() == 0) {
> > @@ -903,21 +906,39 @@
> >
> >        _AudioFeedback(false);
> >
> > +    ExpressionParser parser;
> > +    double value = 0.00;
> > +    BString result;
> > +
> >        // evaluate expression
> > -       BString value;
> > -
> >        try {
> > -               ExpressionParser parser;
> > -               value = parser.Evaluate(expression.String());
> > +               value = parser.EvaluateToDouble(expression.String());
> >        } catch (ParseException e) {
> >                BString error(e.message.String());
> >                error << " at " << (e.position + 1);
> > -               fExpressionTextView->SetText(error.String());
> > -               return;
> > +        // just print error
> > +        result.SetTo("error");
> > +        fExpressionTextView->SetExpression(result.String());
> > +        return;
> >        }
> >
> > +    if (value == 0) {
> > +        result.SetTo("0");
> > +        fExpressionTextView->SetExpression(result.String());
> > +        return;
> > +    } else if (((value < STD_NOTATION_UPPER)
> > +             && (value > STD_NOTATION_LOWER))
> > +             || ((value > -STD_NOTATION_UPPER)
> > +             && (value < -STD_NOTATION_LOWER))) {
> > +        // Standard Notation
> > +        result = parser.EvaluateToStandard(expression.String(), 16);
> > +    } else {
> > +        // Scientific Notation
> > +        result = parser.EvaluateToScientific(expression.String(), 12);
> > +    }
> > +
> >        // render new result to display
> > -       fExpressionTextView->SetExpression(value.String());
> > +       fExpressionTextView->SetExpression(result.String());
> >  }
> >
> >
> > Index: src/kits/shared/ExpressionParser.cpp
> > ===================================================================
> > --- src/kits/shared/ExpressionParser.cpp        (revision 34828)
> > +++ src/kits/shared/ExpressionParser.cpp        (working copy)
> > @@ -317,6 +317,14 @@
> >  BString
> >  ExpressionParser::Evaluate(const char* expressionString) {
> > +    return EvaluateToStandard(expressionString, kMaxDecimalPlaces);
> > +}
> > +
> > +
> > +BString
> > +ExpressionParser::EvaluateToStandard(const char* expressionString,
> > +                                     int32 decimalPlaces)
> > +{
> >        fTokenizer->SetTo(expressionString);
> >
> >        MAPM value = _ParseBinary();
> > @@ -327,11 +335,14 @@
> >        if (value == 0)
> >                return BString("0");
> >
> > -       char* buffer = value.toFixPtStringExp(kMaxDecimalPlaces, '.', 
> > 0, 0);
> > +    if (decimalPlaces <= 0)
> > +        decimalPlaces = kMaxDecimalPlaces;
> > +
> > +       char* buffer = value.toFixPtStringExp(decimalPlaces, '.', 0, 0);
> >        if (buffer == NULL)
> >                throw ParseException("out of memory", 0);
> >
> > -       // remove surplus zeros
> > +       // remove trailing decimal zeros
> >        int32 lastChar = strlen(buffer) - 1;
> >        if (strchr(buffer, '.')) {
> >                while (buffer[lastChar] == '0')
> > @@ -343,6 +354,50 @@
> >        BString result(buffer, lastChar + 1);
> >        free(buffer);
> >        return result;
> > +}
> > +
> > +
> > +BString
> > +ExpressionParser::EvaluateToScientific(const char* expressionString,
> > +                                       int32 decimalPlaces)
> > +{
> > +       fTokenizer->SetTo(expressionString);
> > +
> > +       MAPM value = _ParseBinary();
> > +       Token token = fTokenizer->NextToken();
> > +       if (token.type != TOKEN_END_OF_LINE)
> > +               throw ParseException("parse error", token.position);
> > +
> > +       if (value == 0)
> > +               return BString("0");
> > +
> > +    if (decimalPlaces <= 0)
> > +        decimalPlaces = kMaxDecimalPlaces;
> > +
> > +    // max number of characters possible for 32 bits of decimal places 
> > is
> > +    // decimal places + 15 for -0.9999999....E+2147483647
> > +    // 3 + decimal digits + 2 + 10 = decimalPlaces + 15
> > +       char buffer[decimalPlaces + 15];
> > +    value.toString(buffer, decimalPlaces);
> > +       if (buffer == NULL)
> > +               throw ParseException("out of memory", 0);

"buffer" is stack allocated, the allocation check should be "copy&paste 
left-over". :-)

> > +
> > +       BString result(buffer, decimalPlaces + 15);
> > +
> > +       // remove trailing decimal zeros
> > +    if (result.FindFirst('.') != B_ERROR) {
> > +        int32 offset = result.FindLast('E');
> > +        if (offset != B_ERROR) {
> > +            offset--; // go to character before 'E'
> > +            while(result[offset] == '0') {
> > +                result = result.Remove(offset, sizeof(char));
> > +                offset--;
> > +            }
> > +            if(result[offset] == '.')
> > +                result = result.Remove(offset, sizeof(char));
> > +        }
> > +    }
> > +       return result;
> >  }
> >
> 
> Minor bug in patch:
> if (decimalPlaces <= 0)
>         decimalPlaces = kMaxDecimalPlaces;
> should read:
> if (decimalPlaces < 0)
>         decimalPlaces = kMaxDecimalPlaces;
> 
> Not worth posting another patch, but 0 decimal places is valid.

Thanks for your work! Can you post another version where you use spaces 
instead of tabs? (Maybe it's just an editor setting?)

Best regards,
-Stephan


Other related posts: