| @@ -1,53 +1,52 @@ | |||||
| // | // | ||||
| // Lol Engine - Sample math program: compute Pi | |||||
| // Lol Engine — Sample math program: compute Pi | |||||
| // | // | ||||
| // Copyright: (c) 2005-2011 Sam Hocevar <sam@hocevar.net> | |||||
| // This program is free software; you can redistribute it and/or | |||||
| // modify it under the terms of the Do What The Fuck You Want To | |||||
| // Public License, Version 2, as published by Sam Hocevar. See | |||||
| // http://www.wtfpl.net/ for more details. | |||||
| // Copyright © 2005—2019 Sam Hocevar <sam@hocevar.net> | |||||
| // | |||||
| // This program is free software. It comes without any warranty, to | |||||
| // the extent permitted by applicable law. You can redistribute it | |||||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||||
| // See http://www.wtfpl.net/ for more details. | |||||
| // | // | ||||
| #if HAVE_CONFIG_H | #if HAVE_CONFIG_H | ||||
| # include "config.h" | # include "config.h" | ||||
| #endif | #endif | ||||
| #include <cstdio> | |||||
| #include <iostream> | |||||
| #include <lol/engine.h> | #include <lol/engine.h> | ||||
| using std::printf; | |||||
| using std::sqrt; | |||||
| using lol::real; | using lol::real; | ||||
| int main(int argc, char **argv) | int main(int argc, char **argv) | ||||
| { | { | ||||
| UNUSED(argc, argv); | UNUSED(argc, argv); | ||||
| printf("Pi: "); real::R_PI().print(); | |||||
| printf("e: "); real::R_E().print(); | |||||
| printf("ln(2): "); real::R_LN2().print(); | |||||
| printf("sqrt(2): "); real::R_SQRT2().print(); | |||||
| printf("sqrt(1/2): "); real::R_SQRT1_2().print(); | |||||
| std::cout << " 0: " << real::R_0().str() << '\n'; | |||||
| std::cout << " 1: " << real::R_1().str() << '\n'; | |||||
| std::cout << "sqrt(2): " << real::R_SQRT2().str() << '\n'; | |||||
| std::cout << "sqrt(½): " << real::R_SQRT1_2().str() << '\n'; | |||||
| std::cout << " ln(2): " << real::R_LN2().str() << '\n'; | |||||
| std::cout << " e: " << real::R_E().str() << '\n'; | |||||
| std::cout << " π: " << real::R_PI().str() << '\n'; | |||||
| /* Gauss-Legendre computation of Pi -- doesn't work well at all, | |||||
| * probably because we use finite precision. */ | |||||
| real a = 1.0, b = sqrt((real)0.5), t = 0.25, p = 1.0; | |||||
| // Gauss-Legendre computation of Pi — six iterations are enough for 150 digits | |||||
| real a = 1.0, b = real::R_SQRT1_2(), t = 0.25, p = 1.0; | |||||
| for (int i = 0; i < 3; i++) | |||||
| for (int i = 0; i < 6; i++) | |||||
| { | { | ||||
| real a2 = (a + b) * (real)0.5; | |||||
| real b2 = sqrt(a * b); | |||||
| real tmp = a - a2; | |||||
| real t2 = t - p * tmp * tmp; | |||||
| real p2 = p + p; | |||||
| a = a2; b = b2; t = t2; p = p2; | |||||
| real tmp = (a - b) * (real)0.5; | |||||
| b = sqrt(a * b); | |||||
| a -= tmp; | |||||
| t -= p * tmp * tmp; | |||||
| p += p; | |||||
| } | } | ||||
| real sum = a + b; | real sum = a + b; | ||||
| sum = sum * sum / ((real)4 * t); | sum = sum * sum / ((real)4 * t); | ||||
| sum.print(); | |||||
| std::cout << " " << sum.str() << '\n'; | |||||
| return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||||
| } | } | ||||
| @@ -15,8 +15,7 @@ | |||||
| #endif | #endif | ||||
| #include <memory> | #include <memory> | ||||
| #include <cstring> | |||||
| #include <cstdio> | |||||
| #include <sstream> | |||||
| #include <lol/engine.h> | #include <lol/engine.h> | ||||
| #include "loldebug.h" | #include "loldebug.h" | ||||
| @@ -278,19 +277,12 @@ public: | |||||
| m_zoom_settings[i][1] -= 0.5f * (1.0f - m_zoom_settings[i][2]); | m_zoom_settings[i][1] -= 0.5f * (1.0f - m_zoom_settings[i][2]); | ||||
| } | } | ||||
| char buf[256]; | |||||
| std::sprintf(buf, "center: "); | |||||
| m_view.center.x.sprintf(buf + strlen(buf), 30); | |||||
| std::sprintf(buf + strlen(buf), " "); | |||||
| m_view.center.y.sprintf(buf + strlen(buf), 30); | |||||
| m_centertext->SetText(buf); | |||||
| std::sprintf(buf, " mouse: "); | |||||
| worldmouse.x.sprintf(buf + strlen(buf), 30); | |||||
| std::sprintf(buf + strlen(buf), " "); | |||||
| worldmouse.y.sprintf(buf + strlen(buf), 30); | |||||
| m_mousetext->SetText(buf); | |||||
| std::sprintf(buf, "[%s] zoom: %g", m_julia ? "Julia" : "Mandelbrot", 1.0 / m_view.radius); | |||||
| m_zoomtext->SetText(buf); | |||||
| m_centertext->SetText("center: " + m_view.center.x.str(30) + " " + m_view.center.y.str(30)); | |||||
| m_mousetext->SetText(" mouse: " + worldmouse.x.str(30) + " " + worldmouse.y.str(30)); | |||||
| std::stringstream ss; | |||||
| ss << '[' << (m_julia ? "Julia" : "Mandelbrot") << "] zoom: " << 1.0 / m_view.radius; | |||||
| m_zoomtext->SetText(ss.str()); | |||||
| if (m_dirty[m_frame]) | if (m_dirty[m_frame]) | ||||
| { | { | ||||
| @@ -19,8 +19,9 @@ | |||||
| #include <lol/base/types.h> | #include <lol/base/types.h> | ||||
| #include <cstdint> | |||||
| #include <vector> | #include <vector> | ||||
| #include <string> | |||||
| #include <cstdint> | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -147,10 +148,8 @@ public: | |||||
| template<typename U> friend Real<U> franke(Real<U> const &x, Real<U> const &y); | template<typename U> friend Real<U> franke(Real<U> const &x, Real<U> const &y); | ||||
| template<typename U> friend Real<U> peaks(Real<U> const &x, Real<U> const &y); | template<typename U> friend Real<U> peaks(Real<U> const &x, Real<U> const &y); | ||||
| void xprint() const; | |||||
| void print(int ndigits = 150) const; | |||||
| void sxprintf(char *str) const; | |||||
| void sprintf(char *str, int ndigits = 150) const; | |||||
| std::string str(int ndigits = 150) const; | |||||
| std::string xstr() const; | |||||
| /* Additional operators using base C++ types */ | /* Additional operators using base C++ types */ | ||||
| #define __LOL_REAL_OP_HELPER_GENERIC(op, type) \ | #define __LOL_REAL_OP_HELPER_GENERIC(op, type) \ | ||||
| @@ -359,10 +358,8 @@ template<> real radians(real const &x); | |||||
| template<> real franke(real const &x, real const &y); | template<> real franke(real const &x, real const &y); | ||||
| template<> real peaks(real const &x, real const &y); | template<> real peaks(real const &x, real const &y); | ||||
| template<> void real::xprint() const; | |||||
| template<> void real::print(int ndigits) const; | |||||
| template<> void real::sxprintf(char *str) const; | |||||
| template<> void real::sprintf(char *str, int ndigits) const; | |||||
| template<> std::string real::str(int ndigits) const; | |||||
| template<> std::string real::xstr() const; | |||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| @@ -1,7 +1,7 @@ | |||||
| // | // | ||||
| // Lol Engine | // Lol Engine | ||||
| // | // | ||||
| // Copyright © 2010—2018 Sam Hocevar <sam@hocevar.net> | |||||
| // Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net> | |||||
| // | // | ||||
| // Lol Engine is free software. It comes without any warranty, to | // Lol Engine is free software. It comes without any warranty, to | ||||
| // the extent permitted by applicable law. You can redistribute it | // the extent permitted by applicable law. You can redistribute it | ||||
| @@ -13,6 +13,9 @@ | |||||
| #include <lol/engine-internal.h> | #include <lol/engine-internal.h> | ||||
| #include <new> | #include <new> | ||||
| #include <string> | |||||
| #include <sstream> | |||||
| #include <iomanip> | |||||
| #include <cstring> | #include <cstring> | ||||
| #include <cstdio> | #include <cstdio> | ||||
| #include <cstdlib> | #include <cstdlib> | ||||
| @@ -1560,62 +1563,33 @@ template<> real peaks(real const &x, real const &y) | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| template<> void real::sxprintf(char *str) const; | |||||
| template<> void real::sprintf(char *str, int ndigits) const; | |||||
| template<> void real::xprint() const | |||||
| { | |||||
| char buf[150]; /* 128 bigit digits + room for 0x1, the exponent, etc. */ | |||||
| real::sxprintf(buf); | |||||
| std::printf("%s", buf); | |||||
| } | |||||
| template<> void real::print(int ndigits) const | |||||
| { | |||||
| char *buf = new char[ndigits + 32 + 10]; | |||||
| real::sprintf(buf, ndigits); | |||||
| std::printf("%s", buf); | |||||
| delete[] buf; | |||||
| } | |||||
| template<> void real::sxprintf(char *str) const | |||||
| { | |||||
| if (is_negative()) | |||||
| *str++ = '-'; | |||||
| str += std::sprintf(str, "0x1."); | |||||
| for (int i = 0; i < bigit_count(); ++i) | |||||
| str += std::sprintf(str, "%08x", m_mantissa[i]); | |||||
| while (str[-1] == '0') | |||||
| *--str = '\0'; | |||||
| str += std::sprintf(str, "p%lld", (long long int)m_exponent); | |||||
| } | |||||
| template<> void real::sprintf(char *str, int ndigits) const | |||||
| template<> std::string real::str(int ndigits) const | |||||
| { | { | ||||
| std::stringstream ss; | |||||
| real x = *this; | real x = *this; | ||||
| if (x.is_negative()) | if (x.is_negative()) | ||||
| { | { | ||||
| *str++ = '-'; | |||||
| ss << '-'; | |||||
| x = -x; | x = -x; | ||||
| } | } | ||||
| if (!x) | if (!x) | ||||
| { | { | ||||
| std::strcpy(str, "0"); | |||||
| return; | |||||
| ss << '0'; | |||||
| return ss.str(); | |||||
| } | } | ||||
| /* Normalise x so that mantissa is in [1..9.999] */ | |||||
| /* FIXME: better use int64_t when the cast is implemented */ | |||||
| /* FIXME: does not work with R_MAX and probably R_MIN */ | |||||
| // Normalise x so that mantissa is in [1..9.999] | |||||
| // FIXME: better use int64_t when the cast is implemented | |||||
| // FIXME: does not work with R_MAX and probably R_MIN | |||||
| int exponent = ceil(log10(x)); | int exponent = ceil(log10(x)); | ||||
| x *= pow(R_10(), -(real)exponent); | x *= pow(R_10(), -(real)exponent); | ||||
| if (ndigits < 1) | if (ndigits < 1) | ||||
| ndigits = 1; | ndigits = 1; | ||||
| /* Add a bias to simulate some naive rounding */ | |||||
| // Add a bias to simulate some naive rounding | |||||
| x += real(4.99f) * pow(R_10(), -(real)(ndigits + 1)); | x += real(4.99f) * pow(R_10(), -(real)(ndigits + 1)); | ||||
| if (x < R_1()) | if (x < R_1()) | ||||
| @@ -1624,27 +1598,51 @@ template<> void real::sprintf(char *str, int ndigits) const | |||||
| exponent--; | exponent--; | ||||
| } | } | ||||
| /* Print digits */ | |||||
| // Print digits | |||||
| for (int i = 0; i < ndigits; ++i) | for (int i = 0; i < ndigits; ++i) | ||||
| { | { | ||||
| int digit = (int)floor(x); | int digit = (int)floor(x); | ||||
| *str++ = '0' + digit; | |||||
| ss << (char)('0' + digit); | |||||
| if (i == 0) | if (i == 0) | ||||
| *str++ = '.'; | |||||
| ss << '.'; | |||||
| x -= real(digit); | x -= real(digit); | ||||
| x *= R_10(); | x *= R_10(); | ||||
| } | } | ||||
| /* Remove excess trailing zeroes */ | |||||
| while (str[-1] == '0' && str[-2] != '.') | |||||
| --str; | |||||
| // Remove trailing zeroes | |||||
| std::string ret = ss.str(); | |||||
| ss.str(""); | |||||
| size_t end = ret.find_last_not_of('0'); | |||||
| if (end != std::string::npos) | |||||
| ss << ret.substr(0, end + 1); | |||||
| /* Print exponent information */ | |||||
| // Print exponent information | |||||
| if (exponent) | if (exponent) | ||||
| str += std::sprintf(str, "e%c%i", | |||||
| exponent >= 0 ? '+' : '-', lol::abs(exponent)); | |||||
| ss << 'e' << (exponent >= 0 ? '+' : '-') << lol::abs(exponent); | |||||
| return ss.str(); | |||||
| } | |||||
| template<> std::string real::xstr() const | |||||
| { | |||||
| std::stringstream ss; | |||||
| if (is_negative()) | |||||
| ss << '-'; | |||||
| ss << "0x1." << std::hex; | |||||
| for (int i = 0; i < bigit_count(); ++i) | |||||
| ss << std::setw(8) << m_mantissa[i]; | |||||
| ss << std::dec; | |||||
| // Remove trailing zeroes | |||||
| std::string ret = ss.str(); | |||||
| ss.str(""); | |||||
| size_t end = ret.find_last_not_of('0'); | |||||
| if (end != std::string::npos) | |||||
| ss << ret.substr(0, end + 1); | |||||
| ss << 'p' << m_exponent; | |||||
| *str++ = '\0'; | |||||
| return ss.str(); | |||||
| } | } | ||||
| static real load_min() | static real load_min() | ||||