Quellcode durchsuchen

math: use std::string logic rather than printf() for real number formatting.

legacy
Sam Hocevar vor 5 Jahren
Ursprung
Commit
2bf54ebcb0
4 geänderte Dateien mit 85 neuen und 99 gelöschten Zeilen
  1. +25
    -26
      doc/samples/math/pi.cpp
  2. +7
    -15
      doc/tutorial/11_fractal.cpp
  3. +6
    -9
      src/lol/math/real.h
  4. +47
    -49
      src/math/real.cpp

+ 25
- 26
doc/samples/math/pi.cpp Datei anzeigen

@@ -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;
}


+ 7
- 15
doc/tutorial/11_fractal.cpp Datei anzeigen

@@ -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])
{


+ 6
- 9
src/lol/math/real.h Datei anzeigen

@@ -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 */


+ 47
- 49
src/math/real.cpp Datei anzeigen

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


Laden…
Abbrechen
Speichern