diff --git a/doc/samples/math/pi.cpp b/doc/samples/math/pi.cpp index e3ec6070..2917bdcd 100644 --- a/doc/samples/math/pi.cpp +++ b/doc/samples/math/pi.cpp @@ -1,53 +1,52 @@ // -// Lol Engine - Sample math program: compute Pi +// Lol Engine — Sample math program: compute Pi // -// Copyright: (c) 2005-2011 Sam Hocevar -// 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 +// +// 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 +#include #include -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; } diff --git a/doc/tutorial/11_fractal.cpp b/doc/tutorial/11_fractal.cpp index 1a23321b..31f9f2fc 100644 --- a/doc/tutorial/11_fractal.cpp +++ b/doc/tutorial/11_fractal.cpp @@ -15,8 +15,7 @@ #endif #include -#include -#include +#include #include #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]) { diff --git a/src/lol/math/real.h b/src/lol/math/real.h index 230e3923..7bfc9f80 100644 --- a/src/lol/math/real.h +++ b/src/lol/math/real.h @@ -19,8 +19,9 @@ #include -#include #include +#include +#include namespace lol { @@ -147,10 +148,8 @@ public: template friend Real franke(Real const &x, Real const &y); template friend Real peaks(Real const &x, Real 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 */ diff --git a/src/math/real.cpp b/src/math/real.cpp index 56597b71..b07a00fa 100644 --- a/src/math/real.cpp +++ b/src/math/real.cpp @@ -1,7 +1,7 @@ // // Lol Engine // -// Copyright © 2010—2018 Sam Hocevar +// Copyright © 2010—2019 Sam Hocevar // // 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 #include +#include +#include +#include #include #include #include @@ -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()