Changes from before: Arbint's use a division algorithm based on bitshifting.
So, you might get a random segfault (if you scroll you will definitely get a random segfault)
and pretty much every single operation with Rational<Arbints> gives you an accuracy warning...
And yet somehow I can render a Bezier. Really slowly.
# TODO: stb_truetype doesn't compile with some of these warnings.
CXX = g++ -std=gnu++0x -g -Wall -Werror -Wshadow -pedantic -rdynamic
MAIN = main.o
-OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o vfpu.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o add_digits_asm.o sub_digits_asm.o mul_digits_asm.o arbint.o
+OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o vfpu.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o add_digits_asm.o sub_digits_asm.o mul_digits_asm.o div_digits_asm.o arbint.o
LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL
LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL
namespace IPDF
{
-Arbint::Arbint(digit_t i) : m_digits(1), m_sign(i < 0)
+Arbint::Arbint(int64_t i) : m_digits(1), m_sign(i < 0)
{
m_digits[0] = llabs(i);
}
{
va_list ap;
va_start(ap, d0);
- if (n > 1)
+ if (n >= 1)
m_digits[0] = d0;
for (unsigned i = 1; i < n; ++i)
{
void Arbint::Division(const Arbint & div, Arbint & result, Arbint & remainder) const
{
- if (div == Arbint(1L))
+ remainder = 0;
+ result = 0;
+ for (int i = 8*sizeof(digit_t)*m_digits.size(); i >= 0; --i)
{
- result = *this;
- remainder = 0L;
- return;
- }
- if (div == *this)
- {
- result = 1L;
- remainder = 0L;
- return;
- }
-
-
- result = 0L;
- remainder = *this;
- Arbint next_rem(remainder);
- while ((next_rem -= div) >= Arbint(0L))
- {
- //Debug("%li - %li = %li", digit_t(remainder), digit_t(div), digit_t(next_rem));
- //Debug("Sign is %d", next_rem.m_sign);
- remainder = next_rem;
- result += 1L;
+ remainder <<= 1;
+ if (GetBit(i))
+ remainder.BitSet(0);
+ else
+ remainder.BitClear(0);
+ if (remainder >= div)
+ {
+ remainder -= div;
+ result.BitSet(i);
+ }
}
-
-
}
Arbint & Arbint::operator+=(const Arbint & add)
string Arbint::Str(const string & base) const
{
string s("");
- for (unsigned i = 0; i < m_digits.size(); ++i)
- {
- digit_t w = m_digits[i];
- do
- {
- digit_t q = w % 10;
- w /= 10;
- s += ('0' + q);
- }
- while (w > 0);
- if (i+1 < m_digits.size()) s += ",";
- }
+ Arbint cpy(*this);
+
reverse(s.begin(), s.end());
return s;
}
string Arbint::DigitStr() const
{
stringstream ss("");
- ss << std::hex << std::setfill('0');
+ //ss << std::hex << std::setfill('0');
for (unsigned i = 0; i < m_digits.size(); ++i)
{
if (i != 0) ss << ',';
- ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
+ //ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
+ ss << static_cast<digit_t>(m_digits[i]);
}
return ss.str();
}
+Arbint & Arbint::operator>>=(unsigned amount)
+{
+ // Shift by whole number of digits
+ unsigned whole = amount/(8*sizeof(digit_t));
+ unsigned old_size = m_digits.size();
+
+ if (whole >= old_size)
+ {
+ m_digits.resize(1);
+ m_digits[0] = 0L;
+ return *this;
+ }
+ memmove(m_digits.data(), m_digits.data()+whole, sizeof(digit_t)*(old_size-whole));
+ m_digits.resize(old_size-whole, 0L);
+
+ // Shift by partial amount
+ amount = amount %(8*sizeof(digit_t));
+ if (amount == 0)
+ return *this;
+
+ digit_t underflow = 0L;
+ for (int i = (int)(m_digits.size()-1); i >= 0; --i)
+ {
+ unsigned shl = (8*sizeof(digit_t)-amount);
+ digit_t next_underflow = (m_digits[i] << shl);
+ //digit_t mask_upper = ~(0L >> amount);
+ m_digits[i] = (m_digits[i] >> amount);// & mask_upper;
+ m_digits[i] |= underflow;
+ underflow = next_underflow;
+ }
+ return *this;
+}
+
+Arbint & Arbint::operator<<=(unsigned amount)
+{
+ // Shift by whole number of digits
+ unsigned whole = amount/(8*sizeof(digit_t));
+ unsigned old_size = m_digits.size();
+ m_digits.resize(m_digits.size() + whole);
+ memmove(m_digits.data()+whole, m_digits.data(), sizeof(digit_t)*old_size);
+ memset(m_digits.data(), 0L, whole*sizeof(digit_t));
+
+
+
+ // Partial shifting
+ amount = amount % (8*sizeof(digit_t));
+ if (amount == 0)
+ return *this;
+
+ //Debug("Shift by %u from %u", amount, whole);
+ digit_t overflow = 0L;
+ for (unsigned i = whole; i < m_digits.size(); ++i)
+ {
+ //Debug("Digit is %.16lx", m_digits[i]);
+ unsigned shr = (8*sizeof(digit_t)-amount);
+ //Debug("shr is %u", shr);
+ digit_t next_overflow = (m_digits[i] >> shr);
+ //Debug("Next overflow %.16lx", next_overflow);
+ m_digits[i] <<= amount;
+ //Debug("Before overflow %.16lx", m_digits[i]);
+ m_digits[i] |= overflow;
+ overflow = next_overflow;
+ }
+ if (overflow != 0L)
+ m_digits.push_back(overflow);
+
+ return *this;
+}
+
+bool Arbint::GetBit(unsigned i) const
+{
+ unsigned digit = i/(8*sizeof(digit_t));
+ if (digit > m_digits.size())
+ return false;
+
+ i = i % (8*sizeof(digit_t));
+
+ return (m_digits[digit] & (1L << i));
+
+}
+
+void Arbint::BitClear(unsigned i)
+{
+ unsigned digit = i/(8*sizeof(digit_t));
+ if (digit > m_digits.size())
+ return;
+ i = i % (8*sizeof(digit_t));
+ m_digits[digit] &= ~(1L << i);
+}
+
+void Arbint::BitSet(unsigned i)
+{
+ unsigned digit = i/(8*sizeof(digit_t));
+ if (digit > m_digits.size())
+ {
+ m_digits.resize(digit+1, 0L);
+ }
+ i = i % (8*sizeof(digit_t));
+ m_digits[digit] |= (1L << i);
+}
+
}
class Arbint
{
public:
- typedef int64_t digit_t;
+ typedef uint64_t digit_t;
- Arbint(digit_t i);
+ Arbint(int64_t i);
Arbint(const std::vector<digit_t> & digits);
Arbint(unsigned n, digit_t d0, ...);
Arbint(const std::string & str, const std::string & base="0123456789");
- ~Arbint() {}
+ virtual ~Arbint() {}
Arbint(const Arbint & cpy);
- digit_t AsDigit() const
+ int64_t AsDigit() const
{
- digit_t digit = (m_digits.size() == 1) ? m_digits[0] : 0xFFFFFFFFFFFFFFFF;
+ int64_t digit = (m_digits.size() == 1) ? m_digits[0] : 0x7FFFFFFFFFFFFFFF;
return (m_sign) ? -digit : digit;
}
Arbint & operator*=(const Arbint & mul);
void Division(const Arbint & div, Arbint & result, Arbint & modulo) const;
+ Arbint & operator<<=(unsigned amount);
+ Arbint & operator>>=(unsigned amount);
+
inline Arbint operator+(const Arbint & add) const
{
Arbint a(*this);
{
return !(this->operator<=(grea));
}
-
+ inline Arbint operator>>(unsigned amount) const
+ {
+ Arbint result(*this);
+ result >>= amount;
+ return result;
+ }
+ inline Arbint operator<<(unsigned amount) const
+ {
+ Arbint result(*this);
+ result <<= amount;
+ return result;
+ }
bool IsZero() const;
//inline operator double() const {return double(AsDigit());}
- inline operator digit_t() const {return AsDigit();}
+ inline operator int64_t() const {return AsDigit();}
//inline operator int() const {return int(AsDigit());}
unsigned Shrink();
Arbint & AddBasic(const Arbint & add);
Arbint & SubBasic(const Arbint & sub);
+
+ bool GetBit(unsigned i) const;
+ void BitClear(unsigned i);
+ void BitSet(unsigned i);
+
std::vector<digit_t> m_digits;
bool m_sign;
extern "C"
{
- typedef int64_t digit_t;
+ typedef uint64_t digit_t;
digit_t add_digits(digit_t * dst, digit_t * add, digit_t size);
digit_t sub_digits(digit_t * dst, digit_t * add, digit_t size);
digit_t mul_digits(digit_t * dst, digit_t mul, digit_t size);
+ digit_t div_digits(digit_t * dst, digit_t div, digit_t size, digit_t * rem);
}
}
else
{
doc.AddBezierData(Bezier(0,0,0,1,1,0));
- doc.AddBezierData(Bezier(0,0,1,0,0,1));
- doc.AddBezierData(Bezier(0,0,1,1,1,0));
- doc.AddBezierData(Bezier(0,1,1,0,0,1));
+ //doc.AddBezierData(Bezier(0,0,1,0,0,1));
+ //doc.AddBezierData(Bezier(0,0,1,1,1,0));
+ //doc.AddBezierData(Bezier(0,1,1,0,0,1));
for (int y = 0; y < 8; ++y)
{
//doc.Add(static_cast<IPDF::ObjectType>((x^y)%3), Rect(0.2+x-4.0,0.2+y-4.0,0.6,0.6));
- doc.Add(BEZIER, Rect(0.2+x-4.0, 0.2+y-4.0, 0.6,0.6), (x^y)%3);
+ //doc.Add(BEZIER, Rect(0.2+x-4.0, 0.2+y-4.0, 0.6,0.6), (x^y)%3);
}
-
- //doc.Add(RECT_OUTLINE, Rect(0.1,0.1,0.8,0.8), 0);
- //doc.Add(BEZIER, Rect(0,0,1,1), 0);
}
+ Debug("Make rect");
+ doc.Add(BEZIER, Rect(0.1,0.1,0.8,0.8), 0);
+ Debug("Made rect");
}
+ Debug("Start!");
Rect bounds(b[0],b[1],b[2],b[3]);
if (mode == LOOP)
Rational(double d=0) : P(d*1e6), Q(1e6) // Possibly the worst thing ever...
{
Simplify();
- CheckAccuracy(d, "Construct from double");
+ if (!CheckAccuracy(d, "Construct from double"))
+ {
+ //Fatal("Bwah bwah :(");
+ }
}
Rational(const T & _P, const T & _Q) : P(_P), Q(_Q)
return;
}
T g = gcd(T(llabs(P)),T(llabs(Q)));
- Debug("Got gcd!");
+ //Debug("Got gcd!");
P /= g;
Q /= g;
}
Rational operator+(const Rational & r) const
{
Rational result = (r.P == T(0)) ? Rational(P,Q) : Rational(P*r.Q + r.P*Q, Q*r.Q);
- result.CheckAccuracy(ToDouble() + r.ToDouble(),"+");
+ if (!result.CheckAccuracy(ToDouble() * r.ToDouble(),"+"))
+ {
+ Debug("This is %s (%f) and r is %s (%f)", Str().c_str(), ToDouble(), r.Str().c_str(), r.ToDouble());
+ }
return result;
}
Rational operator-(const Rational & r) const
double ToDouble() const {return (double)(P) / (double)(Q);}
bool CheckAccuracy(double d, const char * msg, double threshold = 1e-3) const
{
- double result = fabs(ToDouble() - d) / d;
+ double result = fabs(ToDouble() - d);
+ if (d != 0e0) result /= d;
if (result > threshold)
{
Warn("(%s) : Rational %s (%f) is not close enough at representing %f (%f vs %f)", msg, Str().c_str(), ToDouble(), d, result, threshold);
+ Backtrace();
return false;
}
return true;
std::string Str() const
{
std::stringstream s;
- s << (int64_t)P << "/" << (int64_t)Q;
+ s << int64_t(P) << "/" << int64_t(Q);
return s.str();
}
#define TEST_CASES 100
-int main(int argc, char ** argv)
+void TestShifting(unsigned cases)
{
-
+ for (unsigned c = 0; c < cases; ++c)
+ {
+ Arbint aa(1u, rand());
+ Arbint bb(aa);
+ for (unsigned i = 0; i < 100*sizeof(Arbint::digit_t); ++i)
+ {
+ bb <<= i;
+ //Debug("i is %u bb is %c%s, a was %c%s", i, bb.SignChar(), bb.DigitStr().c_str(), aa.SignChar(), aa.DigitStr().c_str());
+ bb >>= i;
+ if (bb != aa)
+ {
+ Fatal("i is %u bb is %c%s, a was %c%s", i, bb.SignChar(), bb.DigitStr().c_str(), aa.SignChar(), aa.DigitStr().c_str());
+ }
+ }
+ }
+}
- for (unsigned i = 0; i < TEST_CASES; ++i)
+void TestMaths(unsigned cases)
+{
+ for (unsigned i = 0; i < cases; ++i)
{
- Arbint::digit_t a = rand();
- Arbint::digit_t b = rand();
+ int64_t a = rand();
+ int64_t b = rand();
Arbint arb_a(a);
Arbint arb_b(b);
- Debug("Test %u: a = %li, b = %li", i, a, b);
+ //Debug("Test %u: a = %li, b = %li", i, a, b);
- Debug("a < b = %d", a < b);
- Debug("Arb a<b = %d", arb_a < arb_b);
+ //Debug("a < b = %d", a < b);
+ //Debug("Arb a<b = %d", arb_a < arb_b);
assert((arb_a < arb_b) == (a < b));
- Debug("a > b = %d", a > b);
- Debug("Arb a>b = %d", arb_a > arb_b);
+ //Debug("a > b = %d", a > b);
+ //Debug("Arb a>b = %d", arb_a > arb_b);
assert((arb_a > arb_b) == (a > b));
- Debug("a + b = %.16lx", a+b);
- Debug("Arb a+b = %s", (arb_a+arb_b).DigitStr().c_str());
+ //Debug("a + b = %.16lx", a+b);
+ //Debug("Arb a+b = %s", (arb_a+arb_b).DigitStr().c_str());
assert((arb_a+arb_b).AsDigit() == a + b);
- Debug("a - b = %li %.16lx", (a-b), (a-b));
- Debug("Arb a-b = %s %.16lx", (arb_a-arb_b).DigitStr().c_str(), (arb_a-arb_b).AsDigit());
+ //Debug("a - b = %li %.16lx", (a-b), (a-b));
+ //Debug("Arb a-b = %s %.16lx", (arb_a-arb_b).DigitStr().c_str(), (arb_a-arb_b).AsDigit());
assert((arb_a-arb_b).AsDigit() == a - b);
- Debug("a * b = %.16lx", a*b);
- Debug("Arb a*b = %s", (arb_a*arb_b).DigitStr().c_str());
+ //Debug("a * b = %.16lx", a*b);
+ //Debug("Arb a*b = %s", (arb_a*arb_b).DigitStr().c_str());
assert((arb_a*arb_b).AsDigit() == a * b);
- Debug("a / b = %.16lx", a/b);
- Debug("Arb a/b = %s", (arb_a/arb_b).DigitStr().c_str());
+ //Debug("a / b = %.16lx", a/b);
+ //Debug("Arb a/b = %s", (arb_a/arb_b).DigitStr().c_str());
assert((arb_a/arb_b).AsDigit() == a / b);
assert((arb_a%arb_b).AsDigit() == a % b);
+ }
+}
+
+void TestConstructFromDouble(unsigned cases)
+{
+ for (unsigned c = 0; c < cases; ++c)
+ {
+ int64_t test = (int64_t)(rand()*1e6);
+ double d = (double)(test);
+ Arbint a(d);
+ Arbint b(test);
+ if (a != b)
+ {
+ Fatal("test is %li, d is %f, a is %s, b is %s", test, d, a.DigitStr().c_str(), b.DigitStr().c_str());
+ }
+
+
}
- printf("All single digit tests successful!\n");
+}
+
+int main(int argc, char ** argv)
+{
+ Debug("Shift testing...");
+ TestShifting(TEST_CASES);
+ Debug("Left/Right shift testing succeeded");
+
+ Debug("Testing +-*/%");
+ TestMaths(TEST_CASES);
+ Debug("All (single digit) maths operator tests successful!");
+
+ Debug("Testing construct from double");
+ TestConstructFromDouble(TEST_CASES);
+ Debug("Construct from double successful");
return 0;
}
using namespace std;
using namespace IPDF;
+#include "rect.h"
+
int main(int argc, char ** argv)
{
+
+ Rect rect(0,0,1,1);
+ return 0;
for (unsigned i = 0; i < TEST_CASES; ++i)
{
- Debug("Cycle %u",i);
- Arbint p1 = 1L;//rand();
- Arbint q1 = 2L;//rand();
- Arbint p2 = rand();
- Arbint q2 = rand();
- Debug("Construct rationals");
- Rational<Arbint> a(p1, q1);
- Debug("Constructed a %u\n",i);
- Rational<Arbint> b(p2, q2);
- Debug("Constructed b %u\n",i);
+ double d = (double)(rand()) / (double)(rand());
+ Rational<Arbint> r(d);
+ Debug("%f -> %s -> %s/%s", d, r.Str().c_str(), r.P.DigitStr().c_str(), r.Q.DigitStr().c_str());
+
}