diff --git a/src/real.cpp b/src/real.cpp index 066cb38e..f62b5ec9 100644 --- a/src/real.cpp +++ b/src/real.cpp @@ -121,6 +121,66 @@ real::operator double() const return u.d; } +/* + * Create a real number from an ASCII representation + */ +real::real(char const *str) +{ + real ret = 0; + int exponent = 0; + bool comma = false, nonzero = false, negative = false, finished = false; + + for (char const *p = str; *p && !finished; p++) + { + switch (*p) + { + case '-': + case '+': + if (p != str) + break; + negative = (*p == '-'); + break; + case '.': + if (comma) + finished = true; + comma = true; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (nonzero) + { + real x = ret + ret; + x = x + x + ret; + ret = x + x; + } + if (*p != '0') + { + ret += (int)(*p - '0'); + nonzero = true; + } + if (comma) + exponent--; + break; + case 'e': + case 'E': + exponent += atoi(p + 1); + finished = true; + break; + default: + finished = true; + break; + } + } + + if (exponent) + ret *= pow(R_10, (real)exponent); + + if (negative) + ret = -ret; + + new(this) real(ret); +} + real real::operator +() const { return *this; diff --git a/src/real.h b/src/real.h index 1cbc2328..acaaecfe 100644 --- a/src/real.h +++ b/src/real.h @@ -37,6 +37,8 @@ public: real(int i); real(unsigned int i); + real(char const *str); + operator float() const; operator double() const; operator int() const; diff --git a/test/unit/real.cpp b/test/unit/real.cpp index 6047ce87..70612ef9 100644 --- a/test/unit/real.cpp +++ b/test/unit/real.cpp @@ -103,6 +103,23 @@ LOLUNIT_FIXTURE(RealTest) LOLUNIT_ASSERT_DOUBLES_EQUAL(a6, 1234567876543210.0, 0.0); } + LOLUNIT_TEST(StringToReal) + { + float a1 = real("0"); + float a2 = real("1"); + float a3 = real("-1"); + /* 2^-128 * 2^128 */ + float a4 = real("0.0000000000000000000000000000000000000029387358770" + "557187699218413430556141945466638919302188037718792" + "6569604314863681793212890625") + * real("340282366920938463463374607431768211456"); + + LOLUNIT_ASSERT_EQUAL(a1, 0.0f); + LOLUNIT_ASSERT_EQUAL(a2, 1.0f); + LOLUNIT_ASSERT_EQUAL(a3, -1.0f); + LOLUNIT_ASSERT_EQUAL(a4, 1.0f); + } + LOLUNIT_TEST(UnaryMinus) { float a1 = - real(1.0f);