for the next implementation of large float numbers.undefined
@@ -1,7 +1,7 @@ | |||||
// | // | ||||
// Lol Engine - Sandbox program | // 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 | // This program 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 | ||||
@@ -16,151 +16,17 @@ | |||||
#include <lol/engine.h> | #include <lol/engine.h> | ||||
#include "pegtl.hh" | |||||
namespace lol { namespace parser = pegtl; } | |||||
#include "axe.h" | |||||
namespace lol { using namespace axe; } | |||||
using namespace lol; | 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() | 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/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/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/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/gradient.h lol/math/noise/perlin.h \ | ||||
lol/math/noise/simplex.h \ | lol/math/noise/simplex.h \ | ||||
\ | \ | ||||
@@ -13,6 +13,7 @@ | |||||
#include <lol/math/constants.h> | #include <lol/math/constants.h> | ||||
#include <lol/math/functions.h> | #include <lol/math/functions.h> | ||||
#include <lol/math/half.h> | #include <lol/math/half.h> | ||||
#include <lol/math/bigint.h> | |||||
#include <lol/math/real.h> | #include <lol/math/real.h> | ||||
#include <lol/math/ops.h> | #include <lol/math/ops.h> | ||||
#include <lol/math/vector.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\all.h" /> | ||||
<ClInclude Include="lol\math\array2d.h" /> | <ClInclude Include="lol\math\array2d.h" /> | ||||
<ClInclude Include="lol\math\array3d.h" /> | <ClInclude Include="lol\math\array3d.h" /> | ||||
<ClInclude Include="lol\math\bigint.h" /> | |||||
<ClInclude Include="lol\math\constants.h" /> | <ClInclude Include="lol\math\constants.h" /> | ||||
<ClInclude Include="lol\math\functions.h" /> | <ClInclude Include="lol\math\functions.h" /> | ||||
<ClInclude Include="lol\math\geometry.h" /> | <ClInclude Include="lol\math\geometry.h" /> | ||||
@@ -417,6 +417,9 @@ | |||||
<ClInclude Include="lol\math\all.h"> | <ClInclude Include="lol\math\all.h"> | ||||
<Filter>lol\math</Filter> | <Filter>lol\math</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="lol\math\bigint.h"> | |||||
<Filter>lol\math</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="lol\math\matrix.h"> | <ClInclude Include="lol\math\matrix.h"> | ||||
<Filter>lol\math</Filter> | <Filter>lol\math</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
@@ -20,7 +20,8 @@ test_math_SOURCES = test-common.cpp \ | |||||
math/array2d.cpp math/array3d.cpp math/arraynd.cpp math/box.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/cmplx.cpp math/half.cpp math/interp.cpp math/matrix.cpp \ | ||||
math/quat.cpp math/rand.cpp math/real.cpp math/rotation.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_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tools/lolunit | ||||
test_math_DEPENDENCIES = @LOL_DEPS@ | 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\array3d.cpp" /> | ||||
<ClCompile Include="math\arraynd.cpp" /> | <ClCompile Include="math\arraynd.cpp" /> | ||||
<ClCompile Include="math\box.cpp" /> | <ClCompile Include="math\box.cpp" /> | ||||
<ClCompile Include="math\bigint.cpp" /> | |||||
<ClCompile Include="math\cmplx.cpp" /> | <ClCompile Include="math\cmplx.cpp" /> | ||||
<ClCompile Include="math\half.cpp" /> | <ClCompile Include="math\half.cpp" /> | ||||
<ClCompile Include="math\interp.cpp" /> | <ClCompile Include="math\interp.cpp" /> | ||||