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" /> | |||