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