| @@ -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 | |||
| # include "config.h" | |||
| #endif | |||
| #include <cstdio> | |||
| #include <iostream> | |||
| #include <lol/engine.h> | |||
| using std::printf; | |||
| using std::sqrt; | |||
| using lol::real; | |||
| int main(int argc, char **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; | |||
| sum = sum * sum / ((real)4 * t); | |||
| sum.print(); | |||
| std::cout << " " << sum.str() << '\n'; | |||
| return EXIT_SUCCESS; | |||
| } | |||
| @@ -15,8 +15,7 @@ | |||
| #endif | |||
| #include <memory> | |||
| #include <cstring> | |||
| #include <cstdio> | |||
| #include <sstream> | |||
| #include <lol/engine.h> | |||
| #include "loldebug.h" | |||
| @@ -278,19 +277,12 @@ public: | |||
| 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]) | |||
| { | |||
| @@ -19,8 +19,9 @@ | |||
| #include <lol/base/types.h> | |||
| #include <cstdint> | |||
| #include <vector> | |||
| #include <string> | |||
| #include <cstdint> | |||
| 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> 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 */ | |||
| #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 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 */ | |||
| @@ -1,7 +1,7 @@ | |||
| // | |||
| // 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 | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| @@ -13,6 +13,9 @@ | |||
| #include <lol/engine-internal.h> | |||
| #include <new> | |||
| #include <string> | |||
| #include <sstream> | |||
| #include <iomanip> | |||
| #include <cstring> | |||
| #include <cstdio> | |||
| #include <cstdlib> | |||
| @@ -1560,62 +1563,33 @@ template<> real peaks(real const &x, real const &y) | |||
| 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; | |||
| if (x.is_negative()) | |||
| { | |||
| *str++ = '-'; | |||
| ss << '-'; | |||
| x = -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)); | |||
| x *= pow(R_10(), -(real)exponent); | |||
| if (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)); | |||
| if (x < R_1()) | |||
| @@ -1624,27 +1598,51 @@ template<> void real::sprintf(char *str, int ndigits) const | |||
| exponent--; | |||
| } | |||
| /* Print digits */ | |||
| // Print digits | |||
| for (int i = 0; i < ndigits; ++i) | |||
| { | |||
| int digit = (int)floor(x); | |||
| *str++ = '0' + digit; | |||
| ss << (char)('0' + digit); | |||
| if (i == 0) | |||
| *str++ = '.'; | |||
| ss << '.'; | |||
| x -= real(digit); | |||
| 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) | |||
| 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() | |||