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