@@ -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() | ||||