for the next implementation of large float numbers.undefined
@@ -1,7 +1,7 @@ | |||
// | |||
// Lol Engine - Sandbox program | |||
// | |||
// Copyright © 2005-2015 Sam Hocevar <sam@hocevar.net> | |||
// Copyright © 2005—2015 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 | |||
@@ -16,151 +16,17 @@ | |||
#include <lol/engine.h> | |||
#include "pegtl.hh" | |||
namespace lol { namespace parser = pegtl; } | |||
#include "axe.h" | |||
namespace lol { using namespace axe; } | |||
using namespace lol; | |||
// | |||
// Parser tools for a simple calculator grammar with + - * / | |||
// | |||
struct calculator | |||
{ | |||
void push(double d) { stack.Push(d); } | |||
void pop() { printf("%f\n", stack.Pop()); } | |||
void mul() { auto x = stack.Pop(); stack.Push(stack.Pop() * x); } | |||
void div() { auto x = stack.Pop(); stack.Push(stack.Pop() / x); } | |||
void add() { auto x = stack.Pop(); stack.Push(stack.Pop() + x); } | |||
void sub() { auto x = stack.Pop(); stack.Push(stack.Pop() - x); } | |||
array<double> stack; | |||
}; | |||
static void parse_pegtl(std::string const &str); | |||
static void parse_axe(std::string const &str); | |||
int main() | |||
{ | |||
std::string const str("42+2*(1-1+2+3-4*5)"); | |||
parse_axe(str); | |||
parse_pegtl(str); | |||
return EXIT_SUCCESS; | |||
} | |||
// | |||
// PegTL -- a PEG parser | |||
// | |||
namespace pegtl_parser | |||
{ | |||
using namespace lol::parser; | |||
#define ACTION(name, code) \ | |||
struct name : action_base<name> { \ | |||
static void apply(std::string const &ctx, calculator &c) { \ | |||
code \ | |||
} \ | |||
}; | |||
ACTION( do_number, c.push(atof(ctx.c_str())); ) | |||
ACTION( do_op, | |||
switch (ctx[0]) | |||
{ | |||
case '*': c.mul(); break; | |||
case '/': c.div(); break; | |||
case '+': c.add(); break; | |||
case '-': c.sub(); break; | |||
} ) | |||
ACTION( do_success, c.pop(); ) | |||
#undef ACTION | |||
// number <- <digit> + | |||
struct number : ifapply<plus<digit>, do_number> {}; | |||
// term <- number | "(" expr ")" | |||
struct term : sor<number, | |||
seq<one<'('>, struct expr, one<')'>>> {}; | |||
// factor <- term ( "*" term | "/" term ) * | |||
struct factor : seq<term, | |||
star<ifapply<sor<seq<one<'*'>, term>, | |||
seq<one<'/'>, term>>, do_op>>> {}; | |||
// expr <- factor ( "+" factor | "-" factor ) * | |||
struct expr : seq<factor, | |||
star<ifapply<sor<seq<one<'+'>, factor>, | |||
seq<one<'-'>, factor>>, do_op>>> {}; | |||
// stmt <- expr <end> | |||
struct stmt : ifapply<seq<expr, eof>, do_success> {}; | |||
}; | |||
static void parse_pegtl(std::string const & str) | |||
{ | |||
calculator c; | |||
pegtl::basic_parse_string<pegtl_parser::stmt>(str, c); | |||
} | |||
// | |||
// AXE -- a recursive descent parser (needs right-recursion) | |||
// | |||
template<typename IT> | |||
static void parse_axe_helper(IT i1, IT i2) | |||
{ | |||
calculator c; | |||
double d; | |||
#define ACTION(code) e_ref([&](...) { code }) | |||
r_rule<IT> number, term, factor, factor_tail, expr, expr_tail, stmt; | |||
// number ::= <double> | |||
number = r_double(d) >> ACTION( c.push(d); ); | |||
// term ::= number | ( expr ) | |||
term = number | |||
| '(' & expr & ')'; | |||
// factor ::= term factor_tail | |||
// factor_tail ::= * term factor_tail | |||
// | / term factor_tail | |||
// | ɛ | |||
factor_tail = '*' & term >> ACTION( c.mul(); ) & factor_tail | |||
| '/' & term >> ACTION( c.div(); ) & factor_tail | |||
| r_empty(); | |||
factor = term & factor_tail; | |||
// expr ::= factor expr_tail | |||
// expr_tail ::= + factor expr_tail | |||
// | - factor expr_tail | |||
// | ɛ | |||
expr_tail = '+' & factor >> ACTION( c.add(); ) & expr_tail | |||
| '-' & factor >> ACTION( c.sub(); ) & expr_tail | |||
| r_empty(); | |||
expr = factor & expr_tail; | |||
// stmt ::= expr <end> | |||
// | <fail> | |||
stmt = expr & r_end() >> ACTION( c.pop(); ) | |||
| r_fail([](...) { printf("malformed expression\n"); }); | |||
#undef ACTION | |||
// Evaluate expression | |||
stmt(i1, i2); | |||
} | |||
static void parse_axe(std::string const &str) | |||
{ | |||
return parse_axe_helper(str.begin(), str.end()); | |||
bigint<16> i; | |||
bigint<16> x(2), y(12); | |||
auto z = x + y; | |||
printf("%d\n", (int)z); | |||
bigint<0> lol; | |||
auto w = z + lol; | |||
printf("%d\n", (int)w); | |||
} | |||
@@ -42,7 +42,7 @@ liblolcore_headers = \ | |||
lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ | |||
lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/array2d.h \ | |||
lol/math/array3d.h lol/math/constants.h lol/math/matrix.h lol/math/ops.h \ | |||
lol/math/transform.h lol/math/polynomial.h \ | |||
lol/math/transform.h lol/math/polynomial.h lol/math/bigint.h \ | |||
lol/math/noise/gradient.h lol/math/noise/perlin.h \ | |||
lol/math/noise/simplex.h \ | |||
\ | |||
@@ -13,6 +13,7 @@ | |||
#include <lol/math/constants.h> | |||
#include <lol/math/functions.h> | |||
#include <lol/math/half.h> | |||
#include <lol/math/bigint.h> | |||
#include <lol/math/real.h> | |||
#include <lol/math/ops.h> | |||
#include <lol/math/vector.h> | |||
@@ -0,0 +1,143 @@ | |||
// | |||
// Lol Engine | |||
// | |||
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net> | |||
// | |||
// This library 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. | |||
// | |||
#pragma once | |||
// | |||
// The bigint class | |||
// ---------------- | |||
// | |||
#include <lol/base/types.h> | |||
#include <stdint.h> | |||
namespace lol | |||
{ | |||
/* This is OUR namespace. Don't let Windows headers fuck with it. */ | |||
#undef min | |||
#undef max | |||
/* Avoid issues with NaCl headers */ | |||
#undef log2 | |||
/* | |||
* A bigint stores its digits in an array of integers. The MSB of the | |||
* integers are unused. The highest used bit is the sign bit. | |||
* | |||
* Digits are stored in little endian mode. | |||
*/ | |||
template<unsigned int N = 16, typename T = uint32_t> | |||
class bigint | |||
{ | |||
int const bits_per_digit = sizeof(T) * 8 - 1; | |||
T const digit_mask = ~((T)1 << bits_per_digit); | |||
public: | |||
inline bigint() | |||
{ | |||
} | |||
explicit bigint(int32_t x) | |||
{ | |||
/* FIXME: doesn’t work if sizeof(T) < sizeof(int32_t) */ | |||
for (auto &digit : m_digits) | |||
digit = x >= 0 ? (T)0 : digit_mask; | |||
if (N > 0) | |||
m_digits[0] = x & digit_mask; | |||
} | |||
explicit bigint(uint32_t x) | |||
{ | |||
/* FIXME: doesn’t work if sizeof(T) > sizeof(uint32_t) */ | |||
for (auto &digit : m_digits) | |||
digit = (T)0; | |||
if (N > 0) | |||
m_digits[0] = x & digit_mask; | |||
if (N > 1) | |||
m_digits[1] = x >> bits_per_digit; | |||
} | |||
explicit inline operator uint32_t() const | |||
{ | |||
/* FIXME: doesn’t work if sizeof(T) != sizeof(int32_t) */ | |||
if (N < 1) | |||
return 0; | |||
if (N < 2) | |||
return (uint32_t)(m_digits[0] | |||
| ((m_digits[0] << 1) & ~digit_mask)); | |||
return (uint32_t)(m_digits[0] | (m_digits[1] << bits_per_digit)); | |||
} | |||
inline operator int32_t() const | |||
{ | |||
return (int32_t)(uint32_t)*this; | |||
} | |||
/* | |||
* bigint cast to bigint of different size: we copy all digits then | |||
* pad the rest (if applicable) with zeroes or ones to extend the | |||
* sign bit. | |||
*/ | |||
template<int M> | |||
explicit bigint(bigint<M,T> const &x) | |||
{ | |||
for (int i = 0; i < (N < M) ? N : M; ++i) | |||
m_digits[i] = x.m_digits[i]; | |||
if (N > M) | |||
{ | |||
T padding = x.is_negative() ? digit_mask : (T)0; | |||
for (int i = M; i < N; ++i) | |||
m_digits[i] = padding; | |||
} | |||
} | |||
/* | |||
* bigint addition: we add the digits one-to-one, carrying overflows, | |||
* and replace digits with padding if one of the two operands is | |||
* shorter. | |||
*/ | |||
template<int M> | |||
bigint<(N > M) ? N : M, T> operator +(bigint<M,T> const &x) const | |||
{ | |||
bigint<(N > M) ? N : M, T> ret; | |||
T padding = is_negative() ? digit_mask : (T)0; | |||
T x_padding = x.is_negative() ? digit_mask : (T)0; | |||
T carry(0); | |||
for (int i = 0; i < (N > M) ? N : M; ++i) | |||
{ | |||
T digit = (i < N ? m_digits[i] : padding) | |||
+ (i < M ? x.m_digits[i] : x_padding) | |||
+ carry; | |||
ret.m_digits[i] = digit & digit_mask; | |||
carry = (digit & ~digit_mask) ? T(1) : T(0); | |||
} | |||
return ret; | |||
} | |||
private: | |||
inline bool is_negative() const | |||
{ | |||
if (N < 1) | |||
return false; | |||
return (m_digits[N - 1] & ((T)1 << (bits_per_digit - 1))) != 0; | |||
} | |||
T m_digits[N]; | |||
}; | |||
} /* namespace lol */ | |||
@@ -287,6 +287,7 @@ | |||
<ClInclude Include="lol\math\all.h" /> | |||
<ClInclude Include="lol\math\array2d.h" /> | |||
<ClInclude Include="lol\math\array3d.h" /> | |||
<ClInclude Include="lol\math\bigint.h" /> | |||
<ClInclude Include="lol\math\constants.h" /> | |||
<ClInclude Include="lol\math\functions.h" /> | |||
<ClInclude Include="lol\math\geometry.h" /> | |||
@@ -417,6 +417,9 @@ | |||
<ClInclude Include="lol\math\all.h"> | |||
<Filter>lol\math</Filter> | |||
</ClInclude> | |||
<ClInclude Include="lol\math\bigint.h"> | |||
<Filter>lol\math</Filter> | |||
</ClInclude> | |||
<ClInclude Include="lol\math\matrix.h"> | |||
<Filter>lol\math</Filter> | |||
</ClInclude> | |||
@@ -20,7 +20,8 @@ test_math_SOURCES = test-common.cpp \ | |||
math/array2d.cpp math/array3d.cpp math/arraynd.cpp math/box.cpp \ | |||
math/cmplx.cpp math/half.cpp math/interp.cpp math/matrix.cpp \ | |||
math/quat.cpp math/rand.cpp math/real.cpp math/rotation.cpp \ | |||
math/trig.cpp math/vector.cpp math/polynomial.cpp math/noise/simplex.cpp | |||
math/trig.cpp math/vector.cpp math/polynomial.cpp math/noise/simplex.cpp \ | |||
math/bigint.cpp | |||
test_math_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tools/lolunit | |||
test_math_DEPENDENCIES = @LOL_DEPS@ | |||
@@ -0,0 +1,60 @@ | |||
// | |||
// Lol Engine | |||
// | |||
// Copyright © 2010—2015 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. | |||
// | |||
#include <lol/engine-internal.h> | |||
#include <cmath> | |||
#include <lolunit.h> | |||
namespace lol | |||
{ | |||
lolunit_declare_fixture(bigint_test) | |||
{ | |||
lolunit_declare_test(declaration) | |||
{ | |||
bigint<> a; | |||
bigint<0> b; | |||
bigint<32> c; | |||
} | |||
lolunit_declare_test(int32_cast) | |||
{ | |||
bigint<> a(0), b(1), c(-1); | |||
lolunit_assert_equal((int32_t)a, 0); | |||
lolunit_assert_equal((int32_t)b, 1); | |||
lolunit_assert_equal((int32_t)c, -1); | |||
} | |||
lolunit_declare_test(uint32_cast) | |||
{ | |||
bigint<> a(0), b(1), c(~(uint32_t)0); | |||
lolunit_assert_equal((uint32_t)a, 0); | |||
lolunit_assert_equal((uint32_t)b, 1); | |||
lolunit_assert_equal((uint32_t)c, ~(uint32_t)0); | |||
} | |||
lolunit_declare_test(empty_bigint_is_zero) | |||
{ | |||
bigint<0> a, b(1), c(-1); | |||
lolunit_assert_equal((int)a, 0); | |||
lolunit_assert_equal((int)b, 0); | |||
lolunit_assert_equal((int)c, 0); | |||
} | |||
}; | |||
} /* namespace lol */ | |||
@@ -40,6 +40,7 @@ | |||
<ClCompile Include="math\array3d.cpp" /> | |||
<ClCompile Include="math\arraynd.cpp" /> | |||
<ClCompile Include="math\box.cpp" /> | |||
<ClCompile Include="math\bigint.cpp" /> | |||
<ClCompile Include="math\cmplx.cpp" /> | |||
<ClCompile Include="math\half.cpp" /> | |||
<ClCompile Include="math\interp.cpp" /> | |||