From f9001e59de72aa1682d442d71385eb77a37458aa Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sat, 27 Jun 2015 23:00:12 +0200 Subject: [PATCH] Class FString: Add toFloat(), toDouble() and setNumber(...) for floating point values --- doc/TODO | 1 - src/fbutton.cpp | 2 +- src/fobject.h | 1 + src/fstring.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++ src/fstring.h | 36 ++++++++++++++++++++++++------- test/calculator.cpp | 34 ++++++++++++++--------------- test/fstring.cpp | 32 ++++++++++++++++++++++------ 7 files changed, 124 insertions(+), 34 deletions(-) diff --git a/doc/TODO b/doc/TODO index ff8cf64b..c1d7e575 100644 --- a/doc/TODO +++ b/doc/TODO @@ -21,7 +21,6 @@ Missing Features --------------------------------------- - Multiple lines support for FLabel -- long double to FString + FString to long double - Add a window switcher on the right side of the status bar - Add a scrolling area with on-demand scroll bars for FButtonGroup diff --git a/src/fbutton.cpp b/src/fbutton.cpp index cddbb6c0..7cf51e5f 100644 --- a/src/fbutton.cpp +++ b/src/fbutton.cpp @@ -590,7 +590,7 @@ void FButton::onMouseUp (FMouseEvent* event) setUp(); if ( getGeometryGlobal().contains(event->getGlobalPos()) ) processClick(); - } + } } //---------------------------------------------------------------------- diff --git a/src/fobject.h b/src/fobject.h index 4fc262b7..aee7274a 100644 --- a/src/fobject.h +++ b/src/fobject.h @@ -27,6 +27,7 @@ typedef signed short sInt16; typedef signed int sInt32; typedef int64_t sInt64; +typedef long double lDouble; //---------------------------------------------------------------------- // class FObject diff --git a/src/fstring.cpp b/src/fstring.cpp index e96a90ad..6f657e2a 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -1017,6 +1017,30 @@ uLong FString::toULong() const return num; } +//---------------------------------------------------------------------- +double FString::toDouble() const +{ + wchar_t* p; + register double ret; + + if ( ! this->string || ! *this->string ) + throw std::invalid_argument ("null value"); + + ret = wcstod(this->string, &p); + + if ( p != 0 && *p != '\0' ) + throw std::invalid_argument ("no valid floating point value"); + + if ( errno == ERANGE ) + { + if ( ret >= HUGE_VAL || ret <= -HUGE_VAL ) + throw std::out_of_range ("overflow"); + if ( ret == 0.0l ) + throw std::out_of_range ("underflow"); + } + return ret; +} + //---------------------------------------------------------------------- FString FString::ltrim() const { @@ -1212,6 +1236,34 @@ FString& FString::setNumber (uLong num) return *this; } +//---------------------------------------------------------------------- +FString& FString::setNumber (lDouble num, int precision) +{ + register wchar_t *s; + wchar_t format[20]; // = "%.Lg" + + s = &format[0]; + *s++ = L'%'; + *s++ = L'.'; + + if ( precision > 99 ) + precision = 99; + + if ( precision >= 10 ) + { + *s++ = precision / 10 + L'0'; + *s++ = precision % 10 + L'0'; + } + else + *s++ = precision + L'0'; + + *s++ = L'L'; + *s++ = L'g'; + *s = L'\0'; + + return sprintf(format, num); +} + //---------------------------------------------------------------------- FString& FString::setFormatedNumber (long num, char separator) { diff --git a/src/fstring.h b/src/fstring.h index 2e96c2fc..897d5a37 100644 --- a/src/fstring.h +++ b/src/fstring.h @@ -11,6 +11,7 @@ #include #include // for read errno #include +#include #include // need for va_list, va_start and va_end #include // need for vsprintf #include @@ -44,6 +45,8 @@ typedef signed short sInt16; typedef signed int sInt32; typedef int64_t sInt64; +typedef long double lDouble; + //---------------------------------------------------------------------- // class FString @@ -110,15 +113,17 @@ class FString const char* c_str() const; const std::string toString() const; - FString toLower() const; - FString toUpper() const; + FString toLower() const; + FString toUpper() const; - sInt16 toShort() const; - uInt16 toUShort() const; - int toInt() const; - uInt toUInt() const; - long toLong() const; - uLong toULong() const; + sInt16 toShort() const; + uInt16 toUShort() const; + int toInt() const; + uInt toUInt() const; + long toLong() const; + uLong toULong() const; + float toFloat() const; + double toDouble() const; FString ltrim() const; FString rtrim() const; @@ -145,6 +150,9 @@ class FString FString& setNumber (uInt); FString& setNumber (long); FString& setNumber (uLong); + FString& setNumber (float, int precision=8); + FString& setNumber (double, int precision=11); + FString& setNumber (lDouble, int precision=11); FString& setFormatedNumber (sInt16, char separator='.'); FString& setFormatedNumber (uInt16, char separator='.'); @@ -327,6 +335,10 @@ inline int FString::toInt() const inline uInt FString::toUInt() const { return uInt( toULong() ); } +//---------------------------------------------------------------------- +inline float FString::toFloat() const +{ return float( toDouble() ); } + //---------------------------------------------------------------------- inline std::vector FString::split (std::wstring& s) { return split(FString(s)); } @@ -367,6 +379,14 @@ inline FString& FString::setNumber (int num) inline FString& FString::setNumber (uInt num) { return setNumber (uLong(num)); } +//---------------------------------------------------------------------- +inline FString& FString::setNumber (float num, int precision) +{ return setNumber (lDouble(num), precision); } + +//---------------------------------------------------------------------- +inline FString& FString::setNumber (double num, int precision) +{ return setNumber (lDouble(num), precision); } + //---------------------------------------------------------------------- inline FString& FString::setFormatedNumber (sInt16 num, char separator) { return setFormatedNumber (long(num), separator); } diff --git a/test/calculator.cpp b/test/calculator.cpp index e68c3fad..d1e43f51 100644 --- a/test/calculator.cpp +++ b/test/calculator.cpp @@ -14,7 +14,7 @@ #include "fdialog.h" #include "fmessagebox.h" -const long double PI = 3.141592653589793238L; +const lDouble PI = 3.141592653589793238L; //---------------------------------------------------------------------- // class Button @@ -37,7 +37,7 @@ private: //---------------------------------------------------------------------- Button::Button (FWidget* parent) : FButton(parent) { - checked = false; + checked = false; } //---------------------------------------------------------------------- @@ -129,17 +129,17 @@ class Calc : public FDialog NUM_OF_BUTTONS }; - long double a, b; - uInt max_char; - int last_key; - char infix_operator; - char last_infix_operator; - FString input; - int button_no[Calc::NUM_OF_BUTTONS]; + lDouble a, b; + uInt max_char; + int last_key; + char infix_operator; + char last_infix_operator; + FString input; + int button_no[Calc::NUM_OF_BUTTONS]; struct stack_data { - long double term; + lDouble term; char infix_operator; }; @@ -151,7 +151,7 @@ class Calc : public FDialog virtual void draw(); bool isDataEntryKey(int); bool isOperatorKey(int); - void setDisplay (long double); + void setDisplay (lDouble); void setInfixOperator(char); void clearInfixOperator(); void calcInfixOperator(); @@ -273,7 +273,7 @@ Calc::Calc (FWidget* parent) : FDialog(parent) calculator_buttons[Change_sign]->addAccelerator('#'); calculator_buttons[Equals]->addAccelerator(fc::Fkey_return); calculator_buttons[Equals]->addAccelerator(fc::Fkey_enter); - + } //---------------------------------------------------------------------- @@ -392,7 +392,7 @@ bool Calc::isOperatorKey(int key) }; int* iter = std::find (operators, operators+6, key); - + if ( iter != operators+6 ) return true; else @@ -400,7 +400,7 @@ bool Calc::isOperatorKey(int key) } //---------------------------------------------------------------------- -void Calc::setDisplay (long double d) +void Calc::setDisplay (lDouble d) { char buffer[32]; snprintf (buffer, sizeof(buffer), "%31.11Lg", d); @@ -502,7 +502,7 @@ void Calc::onKeyPress (FKeyEvent* event) } event->accept(); break; - + case fc::Fkey_escape: case fc::Fkey_escape_mintty: FAccelEvent a_ev(Accelerator_Event, getFocusWidget()); @@ -535,7 +535,7 @@ void Calc::onClose (FCloseEvent* event) void Calc::cb_buttonClicked (FWidget*, void* data_ptr) { int key; - long double* x; + lDouble* x; using namespace std; @@ -907,7 +907,7 @@ void Calc::cb_buttonClicked (FWidget*, void* data_ptr) if ( ! input.isEmpty() ) { if ( isDataEntryKey(key) ) - *x = atof(input.c_str()); + *x = input.toDouble(); else { // remove trailing zeros diff --git a/test/fstring.cpp b/test/fstring.cpp index 5c658fac..0069a19d 100644 --- a/test/fstring.cpp +++ b/test/fstring.cpp @@ -1,5 +1,7 @@ // fstring.cpp +#include + #include #include #include @@ -116,21 +118,37 @@ int main (int, char**) << formatStr.sprintf("sqrt(%d) = %d", 16, 4) << std::endl; - FString ulong_str = "123456789"; - uLong ulong_num = ulong_str.toULong(); + uLong ulong_num = FString("123456789").toULong(); std::cout << " toULong: " << ulong_num << std::endl; - FString long_str = "-9876543210"; - long long_num = long_str.toLong(); + long long_num = FString("-9876543210").toLong(); std::cout << " toLong: " << long_num << std::endl; - FString num1, num2; + setlocale(LC_NUMERIC, "C"); + try + { + double double_num = FString("2.7182818284590452353").toDouble(); + std::cout << " toDouble: " << std::setprecision(11) + << double_num << std::endl; + } + catch (const std::invalid_argument& ex) + { + std::cerr << "Invalid argument: " << ex.what() << std::endl; + } + catch (const std::out_of_range& ex) + { + std::cerr << "Out of range: " << ex.what() << std::endl; + } + FString num1, num2, num3; num1.setNumber(137); num2.setNumber(-512); + num3.setNumber(3.141592653589793238L, 12); std::cout << " setNumber: " - << num1 << " (unsigned)" << std::endl; + << num1 << " (unsigned)" << std::endl; std::cout << " setNumber: " - << num2 << " (signed)" << std::endl; + << num2 << " (signed)" << std::endl; + std::cout << " setNumber: " + << num3 << " (long double)" << std::endl; FString fnum1, fnum2; fnum1.setFormatedNumber(0xffffffffffffffff, '\'');